mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-24 18:38:26 +08:00
Compare commits
174 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df32655321 | ||
|
|
1c7edf47e3 | ||
|
|
4f5f9543f7 | ||
|
|
0d3c1b7417 | ||
|
|
e634fee753 | ||
|
|
81c17dc643 | ||
|
|
cb106c7fac | ||
|
|
5a9189b7fe | ||
|
|
160ed0d0e4 | ||
|
|
ed92286178 | ||
|
|
a837a6fb64 | ||
|
|
47328236f7 | ||
|
|
566147c530 | ||
|
|
54fad1ee08 | ||
|
|
8c8e283a88 | ||
|
|
4553bc37f5 | ||
|
|
41b0b21354 | ||
|
|
39b55b0cd7 | ||
|
|
ede01c069e | ||
|
|
aa56e53c4d | ||
|
|
3a723a15bf | ||
|
|
1b2da4eb72 | ||
|
|
6f351d4cee | ||
|
|
dba93d4363 | ||
|
|
b46a94bd96 | ||
|
|
fadd8217e8 | ||
|
|
b0d898054e | ||
|
|
3e84892a28 | ||
|
|
f663f8d60a | ||
|
|
0aeee0ff28 | ||
|
|
140e9cf893 | ||
|
|
89e426e522 | ||
|
|
c77062b660 | ||
|
|
bca2912390 | ||
|
|
ed7177e29d | ||
|
|
12ca3ed556 | ||
|
|
d7de86209c | ||
|
|
e53c6cd559 | ||
|
|
352711c871 | ||
|
|
d304ebc544 | ||
|
|
27291fe5c9 | ||
|
|
f714e47722 | ||
|
|
ce135dd111 | ||
|
|
fb4bfedef4 | ||
|
|
5cbe5d2906 | ||
|
|
b6c15164ac | ||
|
|
1960e96a19 | ||
|
|
7a0fd5adfb | ||
|
|
9ae40cff32 | ||
|
|
0070cab9f1 | ||
|
|
79ae876eeb | ||
|
|
ca35b84308 | ||
|
|
3b4f386900 | ||
|
|
34ef1e908e | ||
|
|
6a3f016920 | ||
|
|
d1ab67cd4c | ||
|
|
0d81f9ff9c | ||
|
|
471bd3c5e5 | ||
|
|
5d4cf8a3c3 | ||
|
|
5a5062ecaf | ||
|
|
13c4b51f69 | ||
|
|
a3ddcc93e5 | ||
|
|
365e51e2e9 | ||
|
|
fd096c4444 | ||
|
|
4c1786e127 | ||
|
|
bfeb59d43f | ||
|
|
aa998b1829 | ||
|
|
c8f5c94683 | ||
|
|
2aea7a3c88 | ||
|
|
9f16691cd6 | ||
|
|
8363819933 | ||
|
|
7d6149dbdf | ||
|
|
b088c40101 | ||
|
|
5b5aab1c9e | ||
|
|
13a4b12ad4 | ||
|
|
3e59d84e6b | ||
|
|
cd987a382a | ||
|
|
fdada41327 | ||
|
|
46d44e6753 | ||
|
|
d63d9873ac | ||
|
|
7eeb7ab51b | ||
|
|
7a2075df51 | ||
|
|
ba5ff54b9a | ||
|
|
8af44b2d45 | ||
|
|
72c989ae11 | ||
|
|
861309d517 | ||
|
|
2f0d64cf41 | ||
|
|
5df8a28403 | ||
|
|
3c9940e076 | ||
|
|
0b11aff105 | ||
|
|
3e4fe06197 | ||
|
|
8bf23f8397 | ||
|
|
10d04549fc | ||
|
|
b4193d50a3 | ||
|
|
0620d31d0a | ||
|
|
a804a5e2fa | ||
|
|
06daffbaab | ||
|
|
b901c08156 | ||
|
|
e27eb63627 | ||
|
|
990a4e5c4c | ||
|
|
7f79d4881d | ||
|
|
2d8643015f | ||
|
|
30f7713af1 | ||
|
|
7ab9db4bbd | ||
|
|
fa7548afaf | ||
|
|
676efa792a | ||
|
|
9ffa1e2744 | ||
|
|
1108b29da0 | ||
|
|
b00d5f6adb | ||
|
|
c6438668f2 | ||
|
|
608adb21e1 | ||
|
|
495cb4c62a | ||
|
|
3048cba1ae | ||
|
|
5b1f5f803e | ||
|
|
0d79e28ec9 | ||
|
|
806be0b537 | ||
|
|
c15b9be7ef | ||
|
|
f6ac2c80ed | ||
|
|
5f19509079 | ||
|
|
4677b11dfb | ||
|
|
b3e9797b0e | ||
|
|
f72deb0478 | ||
|
|
455e97074f | ||
|
|
3e52fa6585 | ||
|
|
48172bc035 | ||
|
|
09d1f82021 | ||
|
|
786e183091 | ||
|
|
0ebac39716 | ||
|
|
10b8a33ab7 | ||
|
|
72b9001b56 | ||
|
|
1efabd44ec | ||
|
|
5e66bd29ff | ||
|
|
2f1114b722 | ||
|
|
4428028146 | ||
|
|
e660a74630 | ||
|
|
8f29d63441 | ||
|
|
98afa6eb5b | ||
|
|
c06971987d | ||
|
|
e385ecf35d | ||
|
|
62fb0b15e0 | ||
|
|
19da1a4ff3 | ||
|
|
a798a40fab | ||
|
|
7982a1373f | ||
|
|
a812637cf0 | ||
|
|
53c4d3945a | ||
|
|
2e7519cf29 | ||
|
|
acad210d57 | ||
|
|
ba5807932e | ||
|
|
59d572ae18 | ||
|
|
14aa8659ee | ||
|
|
59c8ed4ef8 | ||
|
|
b886a0572d | ||
|
|
42755cac8a | ||
|
|
ab1306357e | ||
|
|
fa506f4212 | ||
|
|
364aed858f | ||
|
|
58703597e3 | ||
|
|
5d4b42d519 | ||
|
|
cd55db7ed7 | ||
|
|
ca9b3678dc | ||
|
|
395e802b6b | ||
|
|
f38b92a2e2 | ||
|
|
5c6fef71bd | ||
|
|
f3780baedc | ||
|
|
388656f6e0 | ||
|
|
df60f103cc | ||
|
|
7a977d74dc | ||
|
|
7336c57e80 | ||
|
|
66963ca3ac | ||
|
|
1bb1afd1b7 | ||
|
|
52cfc40c24 | ||
|
|
debb058889 | ||
|
|
3d5e3ac9a0 | ||
|
|
a06cb2e031 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
package-lock.json
|
||||
.DS_Store
|
||||
1205
README.zh-Hans.md
Normal file
1205
README.zh-Hans.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1 +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-35b0a040.cb76da7d.js" rel="prefetch"><link href="dist/css/app.80644c67.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.faba1249.css" rel="preload" as="style"><link href="dist/js/app.e664c97c.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.0c7365d5.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.faba1249.css" rel="stylesheet"><link href="dist/css/app.80644c67.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.0c7365d5.js"></script><script src="dist/js/app.e664c97c.js"></script></body></html>
|
||||
<!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.917aff76.js" rel="prefetch"><link href="dist/js/chunk-2d216b67.2d06497a.js" rel="prefetch"><link href="dist/js/chunk-3a2f3e67.13278516.js" rel="prefetch"><link href="dist/css/app.92b546b0.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.94891485.css" rel="preload" as="style"><link href="dist/js/app.aca24f03.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.6cac1a4d.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.94891485.css" rel="stylesheet"><link href="dist/css/app.92b546b0.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.6cac1a4d.js"></script><script src="dist/js/app.aca24f03.js"></script></body></html>
|
||||
@@ -15,6 +15,7 @@ import { layoutValueList } from './src/utils/constant'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import xmind from './src/parse/xmind'
|
||||
import { simpleDeepClone } from './src/utils'
|
||||
import KeyboardNavigation from './src/KeyboardNavigation'
|
||||
|
||||
// 默认选项配置
|
||||
const defaultOpt = {
|
||||
@@ -52,19 +53,9 @@ const defaultOpt = {
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 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))
|
||||
@@ -133,6 +124,11 @@ class MindMap {
|
||||
mindMap: this
|
||||
})
|
||||
|
||||
// 键盘导航类
|
||||
this.keyboardNavigation = new KeyboardNavigation({
|
||||
mindMap: this
|
||||
})
|
||||
|
||||
// 批量执行类
|
||||
this.batchExecution = new BatchExecution()
|
||||
|
||||
@@ -143,11 +139,7 @@ class MindMap {
|
||||
}, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-01 22:15:22
|
||||
* @Desc: 配置参数处理
|
||||
*/
|
||||
// 配置参数处理
|
||||
handleOpt(opt) {
|
||||
// 检查布局配置
|
||||
if (!layoutValueList.includes(opt.layout)) {
|
||||
@@ -158,12 +150,7 @@ class MindMap {
|
||||
return opt
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 18:47:29
|
||||
* @Desc: 渲染,部分渲染
|
||||
*/
|
||||
// 渲染,部分渲染
|
||||
render() {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.initTheme()
|
||||
@@ -172,11 +159,7 @@ class MindMap {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-08 22:05:11
|
||||
* @Desc: 重新渲染
|
||||
*/
|
||||
// 重新渲染
|
||||
reRender() {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.draw.clear()
|
||||
@@ -186,11 +169,7 @@ class MindMap {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-11 21:16:52
|
||||
* @Desc: 容器尺寸变化,调整尺寸
|
||||
*/
|
||||
// 容器尺寸变化,调整尺寸
|
||||
resize() {
|
||||
this.elRect = this.el.getBoundingClientRect()
|
||||
this.width = this.elRect.width
|
||||
@@ -198,38 +177,22 @@ class MindMap {
|
||||
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)
|
||||
@@ -237,70 +200,40 @@ class MindMap {
|
||||
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)) {
|
||||
@@ -311,20 +244,12 @@ class MindMap {
|
||||
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()
|
||||
@@ -332,12 +257,7 @@ class MindMap {
|
||||
this.reRender()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-21 16:39:13
|
||||
* @Desc: 动态设置思维导图数据,包括节点数据、布局、主题、视图
|
||||
*/
|
||||
// 动态设置思维导图数据,包括节点数据、布局、主题、视图
|
||||
setFullData(data) {
|
||||
if (data.root) {
|
||||
this.setData(data.root)
|
||||
@@ -358,12 +278,7 @@ class MindMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-24 14:42:07
|
||||
* @Desc: 获取思维导图数据,节点树、主题、布局等
|
||||
*/
|
||||
// 获取思维导图数据,节点树、主题、布局等
|
||||
getData(withConfig) {
|
||||
let nodeData = this.command.getCopyData()
|
||||
let data = {}
|
||||
@@ -383,21 +298,13 @@ class MindMap {
|
||||
return simpleDeepClone(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* @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,
|
||||
@@ -405,12 +312,7 @@ class MindMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-06-08 14:12:38
|
||||
* @Desc: 设置只读模式、编辑模式
|
||||
*/
|
||||
// 设置只读模式、编辑模式
|
||||
setMode(mode) {
|
||||
if (!['readonly', 'edit'].includes(mode)) {
|
||||
return
|
||||
|
||||
2507
simple-mind-map/package-lock.json
generated
Normal file
2507
simple-mind-map/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.2.16",
|
||||
"version": "0.2.21",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
32
simple-mind-map/scripts/changeComments.js
Normal file
32
simple-mind-map/scripts/changeComments.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 将/** */类型的注释转换为//类型
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
const entryPath = path.resolve(__dirname, '../src')
|
||||
|
||||
const transform = dir => {
|
||||
let dirs = fs.readdirSync(dir)
|
||||
dirs.forEach(item => {
|
||||
let file = path.join(dir, item)
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
transform(file)
|
||||
} else if (/\.js$/.test(file)) {
|
||||
rewriteComments(file)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const rewriteComments = file => {
|
||||
let content = fs.readFileSync(file, 'utf-8')
|
||||
console.log('当前转换文件:', file)
|
||||
content = content.replace(/\/\*\*[^/]+\*\//g, str => {
|
||||
let res = /@Desc:([^\n]+)\n/g.exec(str)
|
||||
if (res.length > 0) {
|
||||
return '// ' + res[1]
|
||||
}
|
||||
})
|
||||
fs.writeFileSync(file, content)
|
||||
}
|
||||
|
||||
transform(entryPath)
|
||||
rewriteComments(path.join(__dirname, '../index.js'))
|
||||
@@ -1,8 +1,4 @@
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-27 13:16:23
|
||||
* @Desc: 在下一个事件循环里执行任务
|
||||
*/
|
||||
// 在下一个事件循环里执行任务
|
||||
const nextTick = function (fn, ctx) {
|
||||
let pending = false
|
||||
let timerFunc = null
|
||||
@@ -33,28 +29,16 @@ const nextTick = function (fn, ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -67,11 +51,7 @@ class BatchExecution {
|
||||
this.nextTick()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-27 13:09:24
|
||||
* @Desc: 执行队列
|
||||
*/
|
||||
// 执行队列
|
||||
flush() {
|
||||
let fns = this.queue.slice(0)
|
||||
this.queue = []
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
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
|
||||
@@ -21,22 +13,14 @@ class Command {
|
||||
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')
|
||||
@@ -46,11 +30,7 @@ class Command {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 13:12:30
|
||||
* @Desc: 执行命令
|
||||
*/
|
||||
// 执行命令
|
||||
exec(name, ...args) {
|
||||
if (this.commands[name]) {
|
||||
this.commands[name].forEach(fn => {
|
||||
@@ -63,11 +43,7 @@ class Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 13:13:01
|
||||
* @Desc: 添加命令
|
||||
*/
|
||||
// 添加命令
|
||||
add(name, fn) {
|
||||
if (this.commands[name]) {
|
||||
this.commands[name].push(fn)
|
||||
@@ -76,11 +52,7 @@ class Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-15 23:02:41
|
||||
* @Desc: 移除命令
|
||||
*/
|
||||
// 移除命令
|
||||
remove(name, fn) {
|
||||
if (!this.commands[name]) {
|
||||
return
|
||||
@@ -98,11 +70,7 @@ class Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 14:35:43
|
||||
* @Desc: 添加回退数据
|
||||
*/
|
||||
// 添加回退数据
|
||||
addHistory() {
|
||||
let data = this.getCopyData()
|
||||
this.history.push(simpleDeepClone(data))
|
||||
@@ -115,11 +83,7 @@ class Command {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-11 22:34:53
|
||||
* @Desc: 回退
|
||||
*/
|
||||
// 回退
|
||||
back(step = 1) {
|
||||
if (this.activeHistoryIndex - step >= 0) {
|
||||
this.activeHistoryIndex -= step
|
||||
@@ -132,12 +96,7 @@ class Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
@@ -147,11 +106,7 @@ class Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 15:02:58
|
||||
* @Desc: 获取渲染树数据副本
|
||||
*/
|
||||
// 获取渲染树数据副本
|
||||
getCopyData() {
|
||||
return copyRenderTree({}, this.mindMap.renderer.renderTree)
|
||||
}
|
||||
|
||||
@@ -1,296 +1,254 @@
|
||||
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.styleLine(this.line, this.node)
|
||||
// 同级位置占位符
|
||||
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
|
||||
import { bfsWalk, throttle } from './utils'
|
||||
import Base from './layouts/Base'
|
||||
|
||||
// 节点拖动类
|
||||
|
||||
class Drag extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor({ mindMap }) {
|
||||
super(mindMap.renderer)
|
||||
this.mindMap = mindMap
|
||||
this.reset()
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 复位
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
|
||||
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
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.offsetX = x - (node.left * scaleX + translateX)
|
||||
this.offsetY = y - (node.top * scaleY + translateY)
|
||||
this.node = node
|
||||
this.isMousedown = true
|
||||
this.mouseDownX = x
|
||||
this.mouseDownY = y
|
||||
})
|
||||
this.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)
|
||||
}
|
||||
|
||||
// 鼠标松开事件
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
// 创建克隆节点
|
||||
|
||||
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.styleLine(this.line, this.node)
|
||||
// 同级位置占位符
|
||||
this.placeholder = this.draw.rect().fill({
|
||||
color: this.node.style.merge('lineColor', true)
|
||||
})
|
||||
this.mindMap.draw.add(this.clone)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除克隆节点
|
||||
|
||||
removeCloneNode() {
|
||||
if (!this.clone) {
|
||||
return
|
||||
}
|
||||
this.clone.remove()
|
||||
this.line.remove()
|
||||
this.placeholder.remove()
|
||||
}
|
||||
|
||||
// 拖动中
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
// 检测重叠节点
|
||||
|
||||
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 && !node.isRoot) {
|
||||
// && 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:53:09
|
||||
* @Desc: 事件类
|
||||
*/
|
||||
// 事件类
|
||||
class Event extends EventEmitter {
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:53:25
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
constructor(opt = {}) {
|
||||
super()
|
||||
this.opt = opt
|
||||
@@ -34,12 +24,7 @@ class Event extends EventEmitter {
|
||||
this.bind()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 15:52:24
|
||||
* @Desc: 绑定函数上下文
|
||||
*/
|
||||
// 绑定函数上下文
|
||||
bindFn() {
|
||||
this.onDrawClick = this.onDrawClick.bind(this)
|
||||
this.onMousedown = this.onMousedown.bind(this)
|
||||
@@ -48,14 +33,10 @@ class Event extends EventEmitter {
|
||||
this.onMousewheel = this.onMousewheel.bind(this)
|
||||
this.onContextmenu = this.onContextmenu.bind(this)
|
||||
this.onSvgMousedown = this.onSvgMousedown.bind(this)
|
||||
this.onKeyup = this.onKeyup.bind(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:53:43
|
||||
* @Desc: 绑定事件
|
||||
*/
|
||||
// 绑定事件
|
||||
bind() {
|
||||
this.mindMap.svg.on('click', this.onDrawClick)
|
||||
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
|
||||
@@ -69,14 +50,10 @@ class Event extends EventEmitter {
|
||||
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
||||
}
|
||||
this.mindMap.svg.on('contextmenu', this.onContextmenu)
|
||||
window.addEventListener('keyup', this.onKeyup)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 15:40:51
|
||||
* @Desc: 解绑事件
|
||||
*/
|
||||
// 解绑事件
|
||||
unbind() {
|
||||
this.mindMap.svg.off('click', this.onDrawClick)
|
||||
this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
|
||||
@@ -84,32 +61,20 @@ class Event extends EventEmitter {
|
||||
window.removeEventListener('mouseup', this.onMouseup)
|
||||
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
||||
this.mindMap.svg.off('contextmenu', this.onContextmenu)
|
||||
window.removeEventListener('keyup', this.onKeyup)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 13:19:39
|
||||
* @Desc: 画布的单击事件
|
||||
*/
|
||||
// 画布的单击事件
|
||||
onDrawClick(e) {
|
||||
this.emit('draw_click', e)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-16 13:37:30
|
||||
* @Desc: svg画布的鼠标按下事件
|
||||
*/
|
||||
// svg画布的鼠标按下事件
|
||||
onSvgMousedown(e) {
|
||||
this.emit('svg_mousedown', e)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 15:17:35
|
||||
* @Desc: 鼠标按下事件
|
||||
*/
|
||||
// 鼠标按下事件
|
||||
onMousedown(e) {
|
||||
// e.preventDefault()
|
||||
// 鼠标左键
|
||||
@@ -121,12 +86,7 @@ class Event extends EventEmitter {
|
||||
this.emit('mousedown', e, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 15:18:32
|
||||
* @Desc: 鼠标移动事件
|
||||
*/
|
||||
// 鼠标移动事件
|
||||
onMousemove(e) {
|
||||
// e.preventDefault()
|
||||
this.mousemovePos.x = e.clientX
|
||||
@@ -139,23 +99,13 @@ class Event extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @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()
|
||||
@@ -168,15 +118,16 @@ class Event extends EventEmitter {
|
||||
this.emit('mousewheel', e, dir, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-10 22:34:13
|
||||
* @Desc: 鼠标右键菜单事件
|
||||
*/
|
||||
// 鼠标右键菜单事件
|
||||
onContextmenu(e) {
|
||||
e.preventDefault()
|
||||
this.emit('contextmenu', e)
|
||||
}
|
||||
|
||||
// 按键松开事件
|
||||
onKeyup(e) {
|
||||
this.emit('keyup', e)
|
||||
}
|
||||
}
|
||||
|
||||
export default Event
|
||||
|
||||
@@ -3,27 +3,15 @@ import JsPDF from 'jspdf'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
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 = '思维导图', ...args) {
|
||||
if (this[type]) {
|
||||
let result = await this[type](name, ...args)
|
||||
@@ -36,11 +24,7 @@ class Export {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 14:57:40
|
||||
* @Desc: 获取svg数据
|
||||
*/
|
||||
// 获取svg数据
|
||||
async getSvgData() {
|
||||
let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap()
|
||||
// 把图片的url转换成data:url类型,否则导出会丢失图片
|
||||
@@ -57,11 +41,7 @@ class Export {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 15:25:19
|
||||
* @Desc: svg转png
|
||||
*/
|
||||
// svg转png
|
||||
svgToPng(svgSrc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
@@ -99,11 +79,7 @@ class Export {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 15:32:07
|
||||
* @Desc: 在canvas上绘制思维导图背景
|
||||
*/
|
||||
// 在canvas上绘制思维导图背景
|
||||
drawBackgroundToCanvas(ctx, width, height) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let {
|
||||
@@ -139,10 +115,8 @@ class Export {
|
||||
})
|
||||
}
|
||||
|
||||
// 导出为png
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-01 22:09:51
|
||||
* @Desc: 导出为png
|
||||
* 方法1.把svg的图片都转化成data:url格式,再转换
|
||||
* 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
|
||||
*/
|
||||
@@ -160,12 +134,7 @@ class Export {
|
||||
return imgDataUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-08-08 19:23:08
|
||||
* @Desc: 导出为pdf
|
||||
*/
|
||||
// 导出为pdf
|
||||
async pdf(name) {
|
||||
let img = await this.png()
|
||||
let pdf = new JsPDF('', 'pt', 'a4')
|
||||
@@ -197,11 +166,7 @@ class Export {
|
||||
image.src = img
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 15:32:07
|
||||
* @Desc: 在svg上绘制思维导图背景
|
||||
*/
|
||||
// 在svg上绘制思维导图背景
|
||||
drawBackgroundToSvg(svg) {
|
||||
return new Promise(async resolve => {
|
||||
let {
|
||||
@@ -223,11 +188,7 @@ class Export {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 14:54:07
|
||||
* @Desc: 导出为svg
|
||||
*/
|
||||
// 导出为svg
|
||||
async svg(name) {
|
||||
let { node } = await this.getSvgData()
|
||||
node.first().before(SVG(`<title>${name}</title>`))
|
||||
@@ -240,11 +201,7 @@ class Export {
|
||||
return URL.createObjectURL(blob)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-08-03 22:19:17
|
||||
* @Desc: 导出为json
|
||||
*/
|
||||
// 导出为json
|
||||
json(name, withConfig = true) {
|
||||
let data = this.mindMap.getData(withConfig)
|
||||
let str = JSON.stringify(data)
|
||||
@@ -252,11 +209,7 @@ class Export {
|
||||
return URL.createObjectURL(blob)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-08-03 22:24:24
|
||||
* @Desc: 专有文件,其实就是json文件
|
||||
*/
|
||||
// 专有文件,其实就是json文件
|
||||
smm(name, withConfig) {
|
||||
return this.json(name, withConfig)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { keyMap } from './utils/keyMap'
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 15:20:46
|
||||
* @Desc: 快捷按键、命令处理类
|
||||
*/
|
||||
// 快捷按键、命令处理类
|
||||
export default class KeyCommand {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 15:21:32
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
constructor(opt) {
|
||||
this.opt = opt
|
||||
this.mindMap = opt.mindMap
|
||||
@@ -21,51 +13,29 @@ export default class KeyCommand {
|
||||
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: 王林
|
||||
* @Date: 2021-04-24 15:23:22
|
||||
* @Desc: 绑定事件
|
||||
*/
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
window.addEventListener('keydown', e => {
|
||||
if (this.isPause) {
|
||||
@@ -83,11 +53,7 @@ export default class KeyCommand {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 19:24:53
|
||||
* @Desc: 检查键值是否符合
|
||||
*/
|
||||
// 检查键值是否符合
|
||||
checkKey(e, key) {
|
||||
let o = this.getOriginEventCodeArr(e)
|
||||
let k = this.getKeyCodeArr(key)
|
||||
@@ -107,11 +73,7 @@ export default class KeyCommand {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 19:15:19
|
||||
* @Desc: 获取事件对象里的键值数组
|
||||
*/
|
||||
// 获取事件对象里的键值数组
|
||||
getOriginEventCodeArr(e) {
|
||||
let arr = []
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
@@ -129,11 +91,7 @@ export default class KeyCommand {
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 19:40:11
|
||||
* @Desc: 获取快捷键对应的键值数组
|
||||
*/
|
||||
// 获取快捷键对应的键值数组
|
||||
getKeyCodeArr(key) {
|
||||
let keyArr = key.split(/\s*\+\s*/)
|
||||
let arr = []
|
||||
@@ -143,10 +101,8 @@ export default class KeyCommand {
|
||||
return arr
|
||||
}
|
||||
|
||||
// 添加快捷键命令
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 15:23:00
|
||||
* @Desc: 添加快捷键命令
|
||||
* Enter
|
||||
* Tab | Insert
|
||||
* Shift + a
|
||||
@@ -161,12 +117,7 @@ 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]) {
|
||||
@@ -185,11 +136,7 @@ export default class KeyCommand {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-08-14 08:49:58
|
||||
* @Desc: 获取指定快捷键的处理函数
|
||||
*/
|
||||
// 获取指定快捷键的处理函数
|
||||
getShortcutFn(key) {
|
||||
let res = []
|
||||
key.split(/\s*\|\s*/).forEach(item => {
|
||||
|
||||
226
simple-mind-map/src/KeyboardNavigation.js
Normal file
226
simple-mind-map/src/KeyboardNavigation.js
Normal file
@@ -0,0 +1,226 @@
|
||||
import { isKey } from './utils/keyMap'
|
||||
import { bfsWalk } from './utils'
|
||||
|
||||
// 键盘导航类
|
||||
export default class KeyboardNavigation {
|
||||
// 构造函数
|
||||
constructor(opt) {
|
||||
this.opt = opt
|
||||
this.mindMap = opt.mindMap
|
||||
this.onKeyup = this.onKeyup.bind(this)
|
||||
this.mindMap.on('keyup', this.onKeyup)
|
||||
}
|
||||
|
||||
// 处理按键事件
|
||||
onKeyup(e) {
|
||||
;['Left', 'Up', 'Right', 'Down'].forEach(dir => {
|
||||
if (isKey(e, dir)) {
|
||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||
this.focus(dir)
|
||||
} else {
|
||||
let root = this.mindMap.renderer.root
|
||||
this.mindMap.renderer.moveNodeToCenter(root)
|
||||
root.active()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 聚焦到下一个节点
|
||||
focus(dir) {
|
||||
// 当前聚焦的节点
|
||||
let currentActiveNode = this.mindMap.renderer.activeNodeList[0]
|
||||
// 当前聚焦节点的位置信息
|
||||
let currentActiveNodeRect = this.getNodeRect(currentActiveNode)
|
||||
// 寻找的下一个聚焦节点
|
||||
let targetNode = null
|
||||
let targetDis = Infinity
|
||||
// 保存并维护距离最近的节点
|
||||
let checkNodeDis = (rect, node) => {
|
||||
let dis = this.getDistance(currentActiveNodeRect, rect)
|
||||
if (dis < targetDis) {
|
||||
targetNode = node
|
||||
targetDis = dis
|
||||
}
|
||||
}
|
||||
|
||||
// 第一优先级:阴影算法
|
||||
this.getFocusNodeByShadowAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
})
|
||||
|
||||
// 第二优先级:区域算法
|
||||
if (!targetNode) {
|
||||
this.getFocusNodeByAreaAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
})
|
||||
}
|
||||
|
||||
// 第三优先级:简单算法
|
||||
if (!targetNode) {
|
||||
this.getFocusNodeBySimpleAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
})
|
||||
}
|
||||
|
||||
// 找到了则让目标节点聚焦
|
||||
if (targetNode) {
|
||||
this.mindMap.renderer.moveNodeToCenter(targetNode)
|
||||
targetNode.active()
|
||||
}
|
||||
}
|
||||
|
||||
// 1.简单算法
|
||||
getFocusNodeBySimpleAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
}) {
|
||||
// 遍历节点树
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
// 跳过当前聚焦的节点
|
||||
if (node === currentActiveNode) return
|
||||
// 当前遍历到的节点的位置信息
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
let match = false
|
||||
// 按下了左方向键
|
||||
if (dir === 'Left') {
|
||||
// 判断节点是否在当前节点的左侧
|
||||
match = right <= currentActiveNodeRect.left
|
||||
// 按下了右方向键
|
||||
} else if (dir === 'Right') {
|
||||
// 判断节点是否在当前节点的右侧
|
||||
match = left >= currentActiveNodeRect.right
|
||||
// 按下了上方向键
|
||||
} else if (dir === 'Up') {
|
||||
// 判断节点是否在当前节点的上面
|
||||
match = bottom <= currentActiveNodeRect.top
|
||||
// 按下了下方向键
|
||||
} else if (dir === 'Down') {
|
||||
// 判断节点是否在当前节点的下面
|
||||
match = top >= currentActiveNodeRect.bottom
|
||||
}
|
||||
// 符合要求,判断是否是最近的节点
|
||||
if (match) {
|
||||
checkNodeDis(rect, node)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 2.阴影算法
|
||||
getFocusNodeByShadowAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
}) {
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node === currentActiveNode) return
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
let match = false
|
||||
if (dir === 'Left') {
|
||||
match =
|
||||
left < currentActiveNodeRect.left &&
|
||||
top < currentActiveNodeRect.bottom &&
|
||||
bottom > currentActiveNodeRect.top
|
||||
} else if (dir === 'Right') {
|
||||
match =
|
||||
right > currentActiveNodeRect.right &&
|
||||
top < currentActiveNodeRect.bottom &&
|
||||
bottom > currentActiveNodeRect.top
|
||||
} else if (dir === 'Up') {
|
||||
match =
|
||||
top < currentActiveNodeRect.top &&
|
||||
left < currentActiveNodeRect.right &&
|
||||
right > currentActiveNodeRect.left
|
||||
} else if (dir === 'Down') {
|
||||
match =
|
||||
bottom > currentActiveNodeRect.bottom &&
|
||||
left < currentActiveNodeRect.right &&
|
||||
right > currentActiveNodeRect.left
|
||||
}
|
||||
if (match) {
|
||||
checkNodeDis(rect, node)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 3.区域算法
|
||||
getFocusNodeByAreaAlgorithm({
|
||||
currentActiveNode,
|
||||
currentActiveNodeRect,
|
||||
dir,
|
||||
checkNodeDis
|
||||
}) {
|
||||
// 当前聚焦节点的中心点
|
||||
let cX = (currentActiveNodeRect.right + currentActiveNodeRect.left) / 2
|
||||
let cY = (currentActiveNodeRect.bottom + currentActiveNodeRect.top) / 2
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node === currentActiveNode) return
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
// 遍历到的节点的中心点
|
||||
let ccX = (right + left) / 2
|
||||
let ccY = (bottom + top) / 2
|
||||
// 节点的中心点坐标和当前聚焦节点的中心点坐标的差值
|
||||
let offsetX = ccX - cX
|
||||
let offsetY = ccY - cY
|
||||
if (offsetX === 0 && offsetY === 0) return
|
||||
let match = false
|
||||
if (dir === 'Left') {
|
||||
match = offsetX <= 0 && offsetX <= offsetY && offsetX <= -offsetY
|
||||
} else if (dir === 'Right') {
|
||||
match = offsetX > 0 && offsetX >= -offsetY && offsetX >= offsetY
|
||||
} else if (dir === 'Up') {
|
||||
match = offsetY <= 0 && offsetY < offsetX && offsetY < -offsetX
|
||||
} else if (dir === 'Down') {
|
||||
match = offsetY > 0 && -offsetY < offsetX && offsetY > offsetX
|
||||
}
|
||||
if (match) {
|
||||
checkNodeDis(rect, node)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取节点的位置信息
|
||||
getNodeRect(node) {
|
||||
let { scaleX, scaleY, translateX, translateY } =
|
||||
this.mindMap.draw.transform()
|
||||
let { left, top, width, height } = node
|
||||
return {
|
||||
right: (left + width) * scaleX + translateX,
|
||||
bottom: (top + height) * scaleY + translateY,
|
||||
left: left * scaleX + translateX,
|
||||
top: top * scaleY + translateY
|
||||
}
|
||||
}
|
||||
|
||||
// 获取两个节点的距离
|
||||
getDistance(node1Rect, node2Rect) {
|
||||
let center1 = this.getCenter(node1Rect)
|
||||
let center2 = this.getCenter(node2Rect)
|
||||
return Math.sqrt(
|
||||
Math.pow(center1.x - center2.x, 2) + Math.pow(center1.y - center2.y, 2)
|
||||
)
|
||||
}
|
||||
|
||||
// 获取节点的中心点
|
||||
getCenter({ left, right, top, bottom }) {
|
||||
return {
|
||||
x: (left + right) / 2,
|
||||
y: (top + bottom) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// 小地图类
|
||||
class MiniMap {
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:00:45
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
constructor(opt) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.isMousedown = false
|
||||
@@ -19,12 +14,7 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:00:43
|
||||
* @Desc: 获取小地图相关数据
|
||||
*/
|
||||
// 获取小地图相关数据
|
||||
getMiniMap() {
|
||||
const svg = this.mindMap.svg
|
||||
const draw = this.mindMap.draw
|
||||
@@ -61,11 +51,8 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
// 计算小地图的渲染数据
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:05:51
|
||||
* @Desc: 计算小地图的渲染数据
|
||||
* boxWidth:小地图容器的宽度
|
||||
* boxHeight:小地图容器的高度
|
||||
*/
|
||||
@@ -124,12 +111,7 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:22:40
|
||||
* @Desc: 小地图鼠标按下事件
|
||||
*/
|
||||
// 小地图鼠标按下事件
|
||||
onMousedown(e) {
|
||||
this.isMousedown = true
|
||||
this.mousedownPos = {
|
||||
@@ -144,12 +126,7 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:22:55
|
||||
* @Desc: 小地图鼠标移动事件
|
||||
*/
|
||||
// 小地图鼠标移动事件
|
||||
onMousemove(e, sensitivityNum = 5) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
@@ -161,12 +138,7 @@ class MiniMap {
|
||||
this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:23:01
|
||||
* @Desc: 小地图鼠标松开事件
|
||||
*/
|
||||
// 小地图鼠标松开事件
|
||||
onMouseup() {
|
||||
this.isMousedown = false
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,9 @@
|
||||
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
|
||||
@@ -23,11 +15,7 @@ class Select {
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-10 22:36:36
|
||||
* @Desc: 绑定事件
|
||||
*/
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
this.checkInNodes = throttle(this.checkInNodes, 500, this)
|
||||
this.mindMap.on('mousedown', e => {
|
||||
@@ -81,11 +69,7 @@ class Select {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-13 07:55:49
|
||||
* @Desc: 鼠标移动事件
|
||||
*/
|
||||
// 鼠标移动事件
|
||||
onMove(x, y) {
|
||||
// 绘制矩形
|
||||
this.rect.plot([
|
||||
@@ -128,22 +112,14 @@ class Select {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()
|
||||
@@ -156,11 +132,7 @@ class Select {
|
||||
.plot([[x, y]])
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-11 10:20:43
|
||||
* @Desc: 检测在选区里的节点
|
||||
*/
|
||||
// 检测在选区里的节点
|
||||
checkInNodes() {
|
||||
let { scaleX, scaleY, translateX, translateY } =
|
||||
this.mindMap.draw.transform()
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-08-22 21:32:50
|
||||
* @Desc: 节点形状类
|
||||
*/
|
||||
// 节点形状类
|
||||
export default class Shape {
|
||||
constructor(node) {
|
||||
this.node = node
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-08-17 22:32:32
|
||||
* @Desc: 形状需要的padding
|
||||
*/
|
||||
// 形状需要的padding
|
||||
getShapePadding(width, height, paddingX, paddingY) {
|
||||
const shape = this.node.getShape()
|
||||
const defaultPaddingX = 15
|
||||
@@ -64,11 +56,7 @@ export default class Shape {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-08-17 22:22:53
|
||||
* @Desc: 创建形状节点
|
||||
*/
|
||||
// 创建形状节点
|
||||
createShape() {
|
||||
const shape = this.node.getShape()
|
||||
let { width, height } = this.node
|
||||
@@ -104,11 +92,7 @@ export default class Shape {
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-04 09:08:54
|
||||
* @Desc: 创建菱形
|
||||
*/
|
||||
// 创建菱形
|
||||
createDiamond() {
|
||||
let { width, height } = this.node
|
||||
let halfWidth = width / 2
|
||||
@@ -129,11 +113,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-03 16:14:12
|
||||
* @Desc: 创建平行四边形
|
||||
*/
|
||||
// 创建平行四边形
|
||||
createParallelogram() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
@@ -146,11 +126,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-03 16:50:23
|
||||
* @Desc: 创建圆角矩形
|
||||
*/
|
||||
// 创建圆角矩形
|
||||
createRoundedRectangle() {
|
||||
let { width, height } = this.node
|
||||
let halfHeight = height / 2
|
||||
@@ -163,12 +139,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 16:14:08
|
||||
* @Desc: 创建八角矩形
|
||||
*/
|
||||
// 创建八角矩形
|
||||
createOctagonalRectangle() {
|
||||
let w = 5
|
||||
let { width, height } = this.node
|
||||
@@ -184,12 +155,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 20:55:50
|
||||
* @Desc: 创建外三角矩形
|
||||
*/
|
||||
// 创建外三角矩形
|
||||
createOuterTriangularRectangle() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
@@ -204,12 +170,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 20:59:37
|
||||
* @Desc: 创建内三角矩形
|
||||
*/
|
||||
// 创建内三角矩形
|
||||
createInnerTriangularRectangle() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
@@ -224,12 +185,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 21:06:31
|
||||
* @Desc: 创建椭圆
|
||||
*/
|
||||
// 创建椭圆
|
||||
createEllipse() {
|
||||
let { width, height } = this.node
|
||||
let halfWidth = width / 2
|
||||
@@ -242,12 +198,7 @@ export default class Shape {
|
||||
`)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 21:14:04
|
||||
* @Desc: 创建圆
|
||||
*/
|
||||
// 创建圆
|
||||
createCircle() {
|
||||
let { width, height } = this.node
|
||||
let halfWidth = width / 2
|
||||
|
||||
@@ -1,230 +1,167 @@
|
||||
import { tagColorList } from './utils/constant'
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 10:09:08
|
||||
* @Desc: 样式类
|
||||
*/
|
||||
class Style {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 16:01:53
|
||||
* @Desc: 设置背景样式
|
||||
*/
|
||||
static setBackgroundStyle(el, themeConfig) {
|
||||
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
|
||||
el.style.backgroundColor = backgroundColor
|
||||
if (backgroundImage) {
|
||||
el.style.backgroundImage = `url(${backgroundImage})`
|
||||
el.style.backgroundRepeat = backgroundRepeat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 10:10:11
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
constructor(ctx, themeConfig) {
|
||||
this.ctx = ctx
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-12 07:40:14
|
||||
* @Desc: 更新主题配置
|
||||
*/
|
||||
updateThemeConfig(themeConfig) {
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 12:02:55
|
||||
* @Desc: 合并样式
|
||||
*/
|
||||
merge(prop, root, isActive) {
|
||||
// 三级及以下节点
|
||||
let defaultConfig = this.themeConfig.node
|
||||
if (root || rootProp.includes(prop)) {
|
||||
// 直接使用最外层样式
|
||||
defaultConfig = this.themeConfig
|
||||
} else if (this.ctx.isGeneralization) {
|
||||
// 概要节点
|
||||
defaultConfig = this.themeConfig.generalization
|
||||
} else if (this.ctx.layerIndex === 0) {
|
||||
// 根节点
|
||||
defaultConfig = this.themeConfig.root
|
||||
} else if (this.ctx.layerIndex === 1) {
|
||||
// 二级节点
|
||||
defaultConfig = this.themeConfig.second
|
||||
}
|
||||
// 激活状态
|
||||
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||
if (
|
||||
this.ctx.nodeData.data.activeStyle &&
|
||||
this.ctx.nodeData.data.activeStyle[prop] !== undefined
|
||||
) {
|
||||
return this.ctx.nodeData.data.activeStyle[prop]
|
||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||
return defaultConfig.active[prop]
|
||||
}
|
||||
}
|
||||
// 优先使用节点本身的样式
|
||||
return this.getSelfStyle(prop) !== undefined
|
||||
? this.getSelfStyle(prop)
|
||||
: defaultConfig[prop]
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 21:55:57
|
||||
* @Desc: 获取某个样式值
|
||||
*/
|
||||
getStyle(prop, root, isActive) {
|
||||
return this.merge(prop, root, isActive)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: flydreame
|
||||
* @Date: 2022-09-17 12:09:39
|
||||
* @Desc: 获取自身自定义样式
|
||||
*/
|
||||
getSelfStyle(prop) {
|
||||
return this.ctx.nodeData.data[prop]
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 10:12:56
|
||||
* @Desc: 矩形
|
||||
*/
|
||||
rect(node) {
|
||||
this.shape(node)
|
||||
node.radius(this.merge('borderRadius'))
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-12 15:04:28
|
||||
* @Desc: 矩形外的其他形状
|
||||
*/
|
||||
shape(node) {
|
||||
node
|
||||
.fill({
|
||||
color: this.merge('fillColor')
|
||||
})
|
||||
.stroke({
|
||||
color: this.merge('borderColor'),
|
||||
width: this.merge('borderWidth'),
|
||||
dasharray: this.merge('borderDasharray')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 12:07:59
|
||||
* @Desc: 文字
|
||||
*/
|
||||
text(node) {
|
||||
node
|
||||
.fill({
|
||||
color: this.merge('color')
|
||||
})
|
||||
.css({
|
||||
'font-family': this.merge('fontFamily'),
|
||||
'font-size': this.merge('fontSize'),
|
||||
'font-weight': this.merge('fontWeight'),
|
||||
'font-style': this.merge('fontStyle'),
|
||||
'text-decoration': this.merge('textDecoration')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-13 08:14:34
|
||||
* @Desc: html文字节点
|
||||
*/
|
||||
domText(node, fontSizeScale = 1) {
|
||||
node.style.fontFamily = this.merge('fontFamily')
|
||||
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||
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: 王林
|
||||
* @Date: 2021-04-11 14:50:49
|
||||
* @Desc: 连线
|
||||
*/
|
||||
line(node, { width, color, dasharray } = {}) {
|
||||
node.stroke({ width, color, dasharray }).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: 王林
|
||||
* @Date: 2021-04-11 20:03:59
|
||||
* @Desc: 按钮
|
||||
*/
|
||||
iconBtn(node, fillNode) {
|
||||
node.fill({ color: '#808080' })
|
||||
fillNode.fill({ color: '#fff' })
|
||||
}
|
||||
}
|
||||
|
||||
export default Style
|
||||
import { tagColorList } from './utils/constant'
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
|
||||
// 样式类
|
||||
|
||||
class Style {
|
||||
// 设置背景样式
|
||||
|
||||
static setBackgroundStyle(el, themeConfig) {
|
||||
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
|
||||
el.style.backgroundColor = backgroundColor
|
||||
if (backgroundImage) {
|
||||
el.style.backgroundImage = `url(${backgroundImage})`
|
||||
el.style.backgroundRepeat = backgroundRepeat
|
||||
}
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
|
||||
constructor(ctx, themeConfig) {
|
||||
this.ctx = ctx
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 更新主题配置
|
||||
|
||||
updateThemeConfig(themeConfig) {
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 合并样式
|
||||
|
||||
merge(prop, root, isActive) {
|
||||
// 三级及以下节点
|
||||
let defaultConfig = this.themeConfig.node
|
||||
if (root || rootProp.includes(prop)) {
|
||||
// 直接使用最外层样式
|
||||
defaultConfig = this.themeConfig
|
||||
} else if (this.ctx.isGeneralization) {
|
||||
// 概要节点
|
||||
defaultConfig = this.themeConfig.generalization
|
||||
} else if (this.ctx.layerIndex === 0) {
|
||||
// 根节点
|
||||
defaultConfig = this.themeConfig.root
|
||||
} else if (this.ctx.layerIndex === 1) {
|
||||
// 二级节点
|
||||
defaultConfig = this.themeConfig.second
|
||||
}
|
||||
// 激活状态
|
||||
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||
if (
|
||||
this.ctx.nodeData.data.activeStyle &&
|
||||
this.ctx.nodeData.data.activeStyle[prop] !== undefined
|
||||
) {
|
||||
return this.ctx.nodeData.data.activeStyle[prop]
|
||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||
return defaultConfig.active[prop]
|
||||
}
|
||||
}
|
||||
// 优先使用节点本身的样式
|
||||
return this.getSelfStyle(prop) !== undefined
|
||||
? this.getSelfStyle(prop)
|
||||
: defaultConfig[prop]
|
||||
}
|
||||
|
||||
// 获取某个样式值
|
||||
|
||||
getStyle(prop, root, isActive) {
|
||||
return this.merge(prop, root, isActive)
|
||||
}
|
||||
|
||||
// 获取自身自定义样式
|
||||
|
||||
getSelfStyle(prop) {
|
||||
return this.ctx.nodeData.data[prop]
|
||||
}
|
||||
|
||||
// 矩形
|
||||
|
||||
rect(node) {
|
||||
this.shape(node)
|
||||
node.radius(this.merge('borderRadius'))
|
||||
}
|
||||
|
||||
// 矩形外的其他形状
|
||||
|
||||
shape(node) {
|
||||
node.fill({
|
||||
color: this.merge('fillColor')
|
||||
})
|
||||
// 节点使用横线样式,不需要渲染非激活状态的边框样式
|
||||
if (
|
||||
!this.ctx.isRoot &&
|
||||
!this.ctx.isGeneralization &&
|
||||
this.themeConfig.nodeUseLineStyle &&
|
||||
!this.ctx.nodeData.data.isActive
|
||||
) {
|
||||
return
|
||||
}
|
||||
node.stroke({
|
||||
color: this.merge('borderColor'),
|
||||
width: this.merge('borderWidth'),
|
||||
dasharray: this.merge('borderDasharray')
|
||||
})
|
||||
}
|
||||
|
||||
// 文字
|
||||
|
||||
text(node) {
|
||||
node
|
||||
.fill({
|
||||
color: this.merge('color')
|
||||
})
|
||||
.css({
|
||||
'font-family': this.merge('fontFamily'),
|
||||
'font-size': this.merge('fontSize'),
|
||||
'font-weight': this.merge('fontWeight'),
|
||||
'font-style': this.merge('fontStyle'),
|
||||
'text-decoration': this.merge('textDecoration')
|
||||
})
|
||||
}
|
||||
|
||||
// html文字节点
|
||||
|
||||
domText(node, fontSizeScale = 1) {
|
||||
node.style.fontFamily = this.merge('fontFamily')
|
||||
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
||||
}
|
||||
|
||||
// 标签文字
|
||||
|
||||
tagText(node, index) {
|
||||
node
|
||||
.fill({
|
||||
color: tagColorList[index].color
|
||||
})
|
||||
.css({
|
||||
'font-size': '12px'
|
||||
})
|
||||
}
|
||||
|
||||
// 标签矩形
|
||||
|
||||
tagRect(node, index) {
|
||||
node.fill({
|
||||
color: tagColorList[index].background
|
||||
})
|
||||
}
|
||||
|
||||
// 内置图标
|
||||
|
||||
iconNode(node) {
|
||||
node.attr({
|
||||
fill: this.merge('color')
|
||||
})
|
||||
}
|
||||
|
||||
// 连线
|
||||
|
||||
line(node, { width, color, dasharray } = {}) {
|
||||
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
|
||||
}
|
||||
|
||||
// 概要连线
|
||||
|
||||
generalizationLine(node) {
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
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
|
||||
@@ -23,11 +13,7 @@ export default class TextEdit {
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 13:27:04
|
||||
* @Desc: 事件
|
||||
*/
|
||||
// 事件
|
||||
bindEvent() {
|
||||
this.show = this.show.bind(this)
|
||||
// 节点双击事件
|
||||
@@ -54,12 +40,7 @@ export default class TextEdit {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-08-16 16:27:02
|
||||
* @Desc: 注册临时快捷键
|
||||
*/
|
||||
// 注册临时快捷键
|
||||
registerTmpShortcut() {
|
||||
// 注册回车快捷键
|
||||
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
||||
@@ -67,20 +48,12 @@ export default class TextEdit {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()
|
||||
@@ -88,6 +61,9 @@ export default class TextEdit {
|
||||
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)
|
||||
this.textEditNode.addEventListener('keyup', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
document.body.appendChild(this.textEditNode)
|
||||
}
|
||||
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
||||
@@ -104,11 +80,7 @@ export default class TextEdit {
|
||||
this.selectNodeText()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-08-02 23:13:50
|
||||
* @Desc: 选中文本
|
||||
*/
|
||||
// 选中文本
|
||||
selectNodeText() {
|
||||
let selection = window.getSelection()
|
||||
let range = document.createRange()
|
||||
@@ -117,11 +89,7 @@ export default class TextEdit {
|
||||
selection.addRange(range)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-24 13:48:16
|
||||
* @Desc: 隐藏文本编辑框
|
||||
*/
|
||||
// 隐藏文本编辑框
|
||||
hideEditTextBox() {
|
||||
if (!this.showTextEdit) {
|
||||
return
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
/**
|
||||
* 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
|
||||
@@ -24,12 +14,7 @@ class View {
|
||||
this.bind()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 15:38:51
|
||||
* @Desc: 绑定
|
||||
*/
|
||||
// 绑定
|
||||
bind() {
|
||||
// 快捷键
|
||||
this.mindMap.keyCommand.addShortcut('Control+=', () => {
|
||||
@@ -80,12 +65,7 @@ class View {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-11-22 18:30:24
|
||||
* @Desc: 获取当前变换状态数据
|
||||
*/
|
||||
// 获取当前变换状态数据
|
||||
getTransformData() {
|
||||
return {
|
||||
transform: this.mindMap.draw.transform(),
|
||||
@@ -99,12 +79,7 @@ class View {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-11-22 19:54:17
|
||||
* @Desc: 动态设置变换状态数据
|
||||
*/
|
||||
// 动态设置变换状态数据
|
||||
setTransformData(viewData) {
|
||||
if (viewData) {
|
||||
Object.keys(viewData.state).forEach(prop => {
|
||||
@@ -118,55 +93,31 @@ class View {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-07-13 15:49:06
|
||||
* @Desc: 平移x方向
|
||||
*/
|
||||
// 平移x方向
|
||||
translateX(step) {
|
||||
this.x += step
|
||||
this.transform()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:03:53
|
||||
* @Desc: 平移x方式到
|
||||
*/
|
||||
// 平移x方式到
|
||||
translateXTo(x) {
|
||||
this.x = x
|
||||
this.transform()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-07-13 15:48:52
|
||||
* @Desc: 平移y方向
|
||||
*/
|
||||
// 平移y方向
|
||||
translateY(step) {
|
||||
this.y += step
|
||||
this.transform()
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-10-10 14:04:10
|
||||
* @Desc: 平移y方向到
|
||||
*/
|
||||
// 平移y方向到
|
||||
translateYTo(y) {
|
||||
this.y = y
|
||||
this.transform()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 17:13:14
|
||||
* @Desc: 应用变换
|
||||
*/
|
||||
// 应用变换
|
||||
transform() {
|
||||
this.mindMap.draw.transform({
|
||||
scale: this.scale,
|
||||
@@ -176,11 +127,7 @@ class View {
|
||||
this.mindMap.emit('view_data_change', this.getTransformData())
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-11 17:41:35
|
||||
* @Desc: 恢复
|
||||
*/
|
||||
// 恢复
|
||||
reset() {
|
||||
this.scale = 1
|
||||
this.x = 0
|
||||
@@ -188,11 +135,7 @@ class View {
|
||||
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
|
||||
@@ -203,16 +146,19 @@ class View {
|
||||
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)
|
||||
}
|
||||
|
||||
// 设置缩放
|
||||
setScale(scale) {
|
||||
this.scale = scale
|
||||
this.transform()
|
||||
this.mindMap.emit('scale', this.scale)
|
||||
}
|
||||
}
|
||||
|
||||
export default View
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import Node from '../Node'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:24:30
|
||||
* @Desc: 布局基类
|
||||
*/
|
||||
// 布局基类
|
||||
class Base {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:25:16
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
constructor(renderer) {
|
||||
// 渲染实例
|
||||
this.renderer = renderer
|
||||
@@ -22,45 +14,25 @@ class Base {
|
||||
this.root = null
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:39:50
|
||||
* @Desc: 计算节点位置
|
||||
*/
|
||||
// 计算节点位置
|
||||
doLayout() {
|
||||
throw new Error('【computed】方法为必要方法,需要子类进行重写!')
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:41:04
|
||||
* @Desc: 连线
|
||||
*/
|
||||
// 连线
|
||||
renderLine() {
|
||||
throw new Error('【renderLine】方法为必要方法,需要子类进行重写!')
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:42:08
|
||||
* @Desc: 定位展开收缩按钮
|
||||
*/
|
||||
// 定位展开收缩按钮
|
||||
renderExpandBtn() {
|
||||
throw new Error('【renderExpandBtn】方法为必要方法,需要子类进行重写!')
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-30 22:49:28
|
||||
* @Desc: 概要节点
|
||||
*/
|
||||
// 概要节点
|
||||
renderGeneralization() {}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-10 21:30:54
|
||||
* @Desc: 创建节点实例
|
||||
*/
|
||||
// 创建节点实例
|
||||
createNode(data, parent, isRoot, layerIndex) {
|
||||
// 创建节点
|
||||
let newNode = null
|
||||
@@ -98,22 +70,13 @@ class Base {
|
||||
return newNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-16 13:48:43
|
||||
* @Desc: 定位节点到画布中间
|
||||
*/
|
||||
// 定位节点到画布中间
|
||||
setNodeCenter(node) {
|
||||
node.left = (this.mindMap.width - node.width) / 2
|
||||
node.top = (this.mindMap.height - node.height) / 2
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 11:25:52
|
||||
* @Desc: 更新子节点属性
|
||||
*/
|
||||
// 更新子节点属性
|
||||
updateChildren(children, prop, offset) {
|
||||
children.forEach(item => {
|
||||
item[prop] += offset
|
||||
@@ -124,22 +87,14 @@ class Base {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:05:01
|
||||
* @Desc: 二次贝塞尔曲线
|
||||
*/
|
||||
// 二次贝塞尔曲线
|
||||
quadraticCurvePath(x1, y1, x2, y2) {
|
||||
let cx = x1 + (x2 - x1) * 0.2
|
||||
let cy = y1 + (y2 - y1) * 0.8
|
||||
return `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:05:18
|
||||
* @Desc: 三次贝塞尔曲线
|
||||
*/
|
||||
// 三次贝塞尔曲线
|
||||
cubicBezierPath(x1, y1, x2, y2) {
|
||||
let cx1 = x1 + (x2 - x1) / 2
|
||||
let cy1 = y1
|
||||
@@ -148,33 +103,21 @@ class Base {
|
||||
return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-27 19:00:07
|
||||
* @Desc: 获取节点的marginX
|
||||
*/
|
||||
// 获取节点的marginX
|
||||
getMarginX(layerIndex) {
|
||||
return layerIndex === 1
|
||||
? this.mindMap.themeConfig.second.marginX
|
||||
: this.mindMap.themeConfig.node.marginX
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:34:20
|
||||
* @Desc: 获取节点的marginY
|
||||
*/
|
||||
// 获取节点的marginY
|
||||
getMarginY(layerIndex) {
|
||||
return layerIndex === 1
|
||||
? this.mindMap.themeConfig.second.marginY
|
||||
: this.mindMap.themeConfig.node.marginY
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-31 20:53:12
|
||||
* @Desc: 获取节点包括概要在内的宽度
|
||||
*/
|
||||
// 获取节点包括概要在内的宽度
|
||||
getNodeWidthWithGeneralization(node) {
|
||||
return Math.max(
|
||||
node.width,
|
||||
@@ -182,11 +125,7 @@ class Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-31 20:53:12
|
||||
* @Desc: 获取节点包括概要在内的高度
|
||||
*/
|
||||
// 获取节点包括概要在内的高度
|
||||
getNodeHeightWithGeneralization(node) {
|
||||
return Math.max(
|
||||
node.height,
|
||||
@@ -194,10 +133,8 @@ class Base {
|
||||
)
|
||||
}
|
||||
|
||||
// 获取节点的边界值
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-31 09:14:03
|
||||
* @Desc: 获取节点的边界值
|
||||
* dir:生长方向,h(水平)、v(垂直)
|
||||
* isLeft:是否向左生长
|
||||
*/
|
||||
|
||||
@@ -1,430 +1,386 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:25:58
|
||||
* @Desc: 目录组织图
|
||||
*/
|
||||
class CatalogOrganization extends Base {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:26:31
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 14:04:20
|
||||
* @Desc: 布局
|
||||
*/
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedLeftTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustLeftTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:49:32
|
||||
* @Desc: 遍历数据计算节点的left、width、height
|
||||
*/
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
if (parent._node.isRoot) {
|
||||
newNode.top =
|
||||
parent._node.top +
|
||||
parent._node.height +
|
||||
this.getMarginX(layerIndex)
|
||||
}
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
if (isRoot) {
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaWidth = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.width
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginX(layerIndex + 1)
|
||||
: 0
|
||||
}
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:59:25
|
||||
* @Desc: 遍历节点树计算节点的left、top
|
||||
*/
|
||||
computedLeftTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginX = this.getMarginX(layerIndex + 1)
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
if (isRoot) {
|
||||
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
|
||||
let totalLeft = left + marginX
|
||||
node.children.forEach(cur => {
|
||||
cur.left = totalLeft
|
||||
totalLeft += cur.width + marginX
|
||||
})
|
||||
} else {
|
||||
let totalTop = node.top + node.height + marginY + node.expandBtnSize
|
||||
node.children.forEach(cur => {
|
||||
cur.left = node.left + node.width * 0.5
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY + node.expandBtnSize
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 10:04:05
|
||||
* @Desc: 调整节点left、top
|
||||
*/
|
||||
adjustLeftTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 调整left
|
||||
if (parent && parent.isRoot) {
|
||||
let areaWidth = this.getNodeAreaWidth(node)
|
||||
let difference = areaWidth - node.width
|
||||
if (difference > 0) {
|
||||
this.updateBrothersLeft(node, difference / 2)
|
||||
}
|
||||
}
|
||||
// 调整top
|
||||
let len = node.children.length
|
||||
if (parent && !parent.isRoot && len > 0) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
let totalHeight =
|
||||
node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * marginY +
|
||||
len * node.expandBtnSize
|
||||
this.updateBrothersTop(node, totalHeight)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-12 18:55:03
|
||||
* @Desc: 递归计算节点的宽度
|
||||
*/
|
||||
getNodeAreaWidth(node) {
|
||||
let widthArr = []
|
||||
let loop = (node, width) => {
|
||||
if (node.children.length) {
|
||||
width += node.width / 2
|
||||
node.children.forEach(item => {
|
||||
loop(item, width)
|
||||
})
|
||||
} else {
|
||||
width += node.width
|
||||
widthArr.push(width)
|
||||
}
|
||||
}
|
||||
loop(node, 0)
|
||||
return Math.max(...widthArr)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-07-13 11:12:51
|
||||
* @Desc: 调整兄弟节点的left
|
||||
*/
|
||||
updateBrothersLeft(node, addWidth) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
// 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称
|
||||
if (
|
||||
(index === 0 || index === childrenList.length - 1) &&
|
||||
childrenList.length > 1
|
||||
) {
|
||||
let _offset = index === 0 ? -addWidth : addWidth
|
||||
node.left += _offset
|
||||
if (
|
||||
node.children &&
|
||||
node.children.length &&
|
||||
!node.hasCustomPosition()
|
||||
) {
|
||||
this.updateChildren(node.children, 'left', _offset)
|
||||
}
|
||||
}
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
if (_index < index) {
|
||||
// 左边的节点往左移
|
||||
_offset = -addWidth
|
||||
} else if (_index > index) {
|
||||
// 右边的节点往右移
|
||||
_offset = addWidth
|
||||
}
|
||||
item.left += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'left', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothersLeft(node.parent, addWidth)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:26:03
|
||||
* @Desc: 调整兄弟节点的top
|
||||
*/
|
||||
updateBrothersTop(node, addHeight) {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 下面的节点往下移
|
||||
if (_index > index) {
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothersTop(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 14:42:48
|
||||
* @Desc: 绘制连线,连接该节点到其子节点
|
||||
*/
|
||||
renderLine(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let len = node.children.length
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
if (node.isRoot) {
|
||||
// 根节点
|
||||
let x1 = left + width / 2
|
||||
let y1 = top + height
|
||||
let s1 = marginX * 0.7
|
||||
let minx = Infinity
|
||||
let maxx = -Infinity
|
||||
node.children.forEach((item, index) => {
|
||||
let x2 = item.left + item.width / 2
|
||||
let y2 = item.top
|
||||
if (x2 < minx) {
|
||||
minx = x2
|
||||
}
|
||||
if (x2 > maxx) {
|
||||
maxx = x2
|
||||
}
|
||||
let path = `M ${x2},${y1 + s1} L ${x2},${
|
||||
y1 + s1 > y2 ? y2 + item.height : y2
|
||||
}`
|
||||
// 竖线
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
minx = Math.min(minx, x1)
|
||||
maxx = Math.max(maxx, x1)
|
||||
// 父节点的竖线
|
||||
let line1 = this.draw.path()
|
||||
node.style.line(line1)
|
||||
line1.plot(`M ${x1},${y1} L ${x1},${y1 + s1}`)
|
||||
node._lines.push(line1)
|
||||
style && style(line1, node)
|
||||
// 水平线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
node.style.line(lin2)
|
||||
lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`)
|
||||
node._lines.push(lin2)
|
||||
style && style(lin2, node)
|
||||
}
|
||||
} else {
|
||||
// 非根节点
|
||||
let y1 = top + height
|
||||
let maxy = -Infinity
|
||||
let x2 = node.left + node.width * 0.3
|
||||
node.children.forEach((item, index) => {
|
||||
// 为了适配自定义位置,下面做了各种位置的兼容
|
||||
let y2 = item.top + item.height / 2
|
||||
if (y2 > maxy) {
|
||||
maxy = y2
|
||||
}
|
||||
// 水平线
|
||||
let path = ''
|
||||
let _left = item.left
|
||||
let _isLeft = item.left + item.width < x2
|
||||
let _isXCenter = false
|
||||
if (_isLeft) {
|
||||
// 水平位置在父节点左边
|
||||
_left = item.left + item.width
|
||||
} else if (item.left < x2 && item.left + item.width > x2) {
|
||||
// 水平位置在父节点之间
|
||||
_isXCenter = true
|
||||
y2 = item.top
|
||||
maxy = y2
|
||||
}
|
||||
if (y2 > top && y2 < y1) {
|
||||
// 自定义位置的情况:垂直位置节点在父节点之间
|
||||
path = `M ${
|
||||
_isLeft ? node.left : node.left + node.width
|
||||
},${y2} L ${_left},${y2}`
|
||||
} else if (y2 < y1) {
|
||||
// 自定义位置的情况:垂直位置节点在父节点上面
|
||||
if (_isXCenter) {
|
||||
y2 = item.top + item.height
|
||||
_left = x2
|
||||
}
|
||||
path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}`
|
||||
} else {
|
||||
if (_isXCenter) {
|
||||
_left = x2
|
||||
}
|
||||
path = `M ${x2},${y2} L ${_left},${y2}`
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
node.style.line(lin2)
|
||||
if (maxy < y1 + expandBtnSize) {
|
||||
lin2.hide()
|
||||
} else {
|
||||
lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`)
|
||||
lin2.show()
|
||||
}
|
||||
node._lines.push(lin2)
|
||||
style && style(lin2, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:54:26
|
||||
* @Desc: 渲染按钮
|
||||
*/
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height, expandBtnSize, isRoot } = node
|
||||
if (!isRoot) {
|
||||
let { translateX, translateY } = btn.transform()
|
||||
btn.translate(
|
||||
width * 0.3 - expandBtnSize / 2 - translateX,
|
||||
height + expandBtnSize / 2 - translateY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-30 08:30:35
|
||||
* @Desc: 创建概要节点
|
||||
*/
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let y1 = top
|
||||
let x2 = right + generalizationLineMargin
|
||||
let y2 = bottom
|
||||
let cx = x1 + 20
|
||||
let cy = y1 + (y2 - y1) / 2
|
||||
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
gLine.plot(path)
|
||||
gNode.left = right + generalizationNodeMargin
|
||||
gNode.top = top + (bottom - top - gNode.height) / 2
|
||||
}
|
||||
}
|
||||
|
||||
export default CatalogOrganization
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 目录组织图
|
||||
|
||||
class CatalogOrganization extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedLeftTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustLeftTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
if (parent._node.isRoot) {
|
||||
newNode.top =
|
||||
parent._node.top +
|
||||
parent._node.height +
|
||||
this.getMarginX(layerIndex)
|
||||
}
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
if (isRoot) {
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaWidth = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.width
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginX(layerIndex + 1)
|
||||
: 0
|
||||
}
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的left、top
|
||||
|
||||
computedLeftTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginX = this.getMarginX(layerIndex + 1)
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
if (isRoot) {
|
||||
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
|
||||
let totalLeft = left + marginX
|
||||
node.children.forEach(cur => {
|
||||
cur.left = totalLeft
|
||||
totalLeft += cur.width + marginX
|
||||
})
|
||||
} else {
|
||||
let totalTop = node.top + node.height + marginY + node.expandBtnSize
|
||||
node.children.forEach(cur => {
|
||||
cur.left = node.left + node.width * 0.5
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY + node.expandBtnSize
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点left、top
|
||||
|
||||
adjustLeftTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 调整left
|
||||
if (parent && parent.isRoot) {
|
||||
let areaWidth = this.getNodeAreaWidth(node)
|
||||
let difference = areaWidth - node.width
|
||||
if (difference > 0) {
|
||||
this.updateBrothersLeft(node, difference / 2)
|
||||
}
|
||||
}
|
||||
// 调整top
|
||||
let len = node.children.length
|
||||
if (parent && !parent.isRoot && len > 0) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
let totalHeight =
|
||||
node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * marginY +
|
||||
len * node.expandBtnSize
|
||||
this.updateBrothersTop(node, totalHeight)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 递归计算节点的宽度
|
||||
|
||||
getNodeAreaWidth(node) {
|
||||
let widthArr = []
|
||||
let loop = (node, width) => {
|
||||
if (node.children.length) {
|
||||
width += node.width / 2
|
||||
node.children.forEach(item => {
|
||||
loop(item, width)
|
||||
})
|
||||
} else {
|
||||
width += node.width
|
||||
widthArr.push(width)
|
||||
}
|
||||
}
|
||||
loop(node, 0)
|
||||
return Math.max(...widthArr)
|
||||
}
|
||||
|
||||
// 调整兄弟节点的left
|
||||
|
||||
updateBrothersLeft(node, addWidth) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
// 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称
|
||||
if (
|
||||
(index === 0 || index === childrenList.length - 1) &&
|
||||
childrenList.length > 1
|
||||
) {
|
||||
let _offset = index === 0 ? -addWidth : addWidth
|
||||
node.left += _offset
|
||||
if (
|
||||
node.children &&
|
||||
node.children.length &&
|
||||
!node.hasCustomPosition()
|
||||
) {
|
||||
this.updateChildren(node.children, 'left', _offset)
|
||||
}
|
||||
}
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
if (_index < index) {
|
||||
// 左边的节点往左移
|
||||
_offset = -addWidth
|
||||
} else if (_index > index) {
|
||||
// 右边的节点往右移
|
||||
_offset = addWidth
|
||||
}
|
||||
item.left += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'left', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothersLeft(node.parent, addWidth)
|
||||
}
|
||||
}
|
||||
|
||||
// 调整兄弟节点的top
|
||||
|
||||
updateBrothersTop(node, addHeight) {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 下面的节点往下移
|
||||
if (_index > index) {
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothersTop(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let len = node.children.length
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
if (node.isRoot) {
|
||||
// 根节点
|
||||
let x1 = left + width / 2
|
||||
let y1 = top + height
|
||||
let s1 = marginX * 0.7
|
||||
let minx = Infinity
|
||||
let maxx = -Infinity
|
||||
node.children.forEach((item, index) => {
|
||||
let x2 = item.left + item.width / 2
|
||||
let y2 = item.top
|
||||
if (x2 < minx) {
|
||||
minx = x2
|
||||
}
|
||||
if (x2 > maxx) {
|
||||
maxx = x2
|
||||
}
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path =
|
||||
`M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` +
|
||||
nodeUseLineStylePath
|
||||
// 竖线
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
minx = Math.min(minx, x1)
|
||||
maxx = Math.max(maxx, x1)
|
||||
// 父节点的竖线
|
||||
let line1 = this.draw.path()
|
||||
node.style.line(line1)
|
||||
line1.plot(`M ${x1},${y1} L ${x1},${y1 + s1}`)
|
||||
node._lines.push(line1)
|
||||
style && style(line1, node)
|
||||
// 水平线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
node.style.line(lin2)
|
||||
lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`)
|
||||
node._lines.push(lin2)
|
||||
style && style(lin2, node)
|
||||
}
|
||||
} else {
|
||||
// 非根节点
|
||||
let y1 = top + height
|
||||
let maxy = -Infinity
|
||||
let x2 = node.left + node.width * 0.3
|
||||
node.children.forEach((item, index) => {
|
||||
// 为了适配自定义位置,下面做了各种位置的兼容
|
||||
let y2 = item.top + item.height / 2
|
||||
if (y2 > maxy) {
|
||||
maxy = y2
|
||||
}
|
||||
// 水平线
|
||||
let path = ''
|
||||
let _left = item.left
|
||||
let _isLeft = item.left + item.width < x2
|
||||
let _isXCenter = false
|
||||
if (_isLeft) {
|
||||
// 水平位置在父节点左边
|
||||
_left = item.left + item.width
|
||||
} else if (item.left < x2 && item.left + item.width > x2) {
|
||||
// 水平位置在父节点之间
|
||||
_isXCenter = true
|
||||
y2 = item.top
|
||||
maxy = y2
|
||||
}
|
||||
if (y2 > top && y2 < y1) {
|
||||
// 自定义位置的情况:垂直位置节点在父节点之间
|
||||
path = `M ${
|
||||
_isLeft ? node.left : node.left + node.width
|
||||
},${y2} L ${_left},${y2}`
|
||||
} else if (y2 < y1) {
|
||||
// 自定义位置的情况:垂直位置节点在父节点上面
|
||||
if (_isXCenter) {
|
||||
y2 = item.top + item.height
|
||||
_left = x2
|
||||
}
|
||||
path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}`
|
||||
} else {
|
||||
if (_isXCenter) {
|
||||
_left = x2
|
||||
}
|
||||
path = `M ${x2},${y2} L ${_left},${y2}`
|
||||
}
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${_left},${y2 - item.height / 2} L ${_left},${
|
||||
y2 + item.height / 2
|
||||
}`
|
||||
: ''
|
||||
path += nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
node.style.line(lin2)
|
||||
if (maxy < y1 + expandBtnSize) {
|
||||
lin2.hide()
|
||||
} else {
|
||||
lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`)
|
||||
lin2.show()
|
||||
}
|
||||
node._lines.push(lin2)
|
||||
style && style(lin2, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height, expandBtnSize, isRoot } = node
|
||||
if (!isRoot) {
|
||||
let { translateX, translateY } = btn.transform()
|
||||
btn.translate(
|
||||
width * 0.3 - expandBtnSize / 2 - translateX,
|
||||
height + expandBtnSize / 2 - translateY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let y1 = top
|
||||
|
||||
@@ -1,308 +1,267 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:25:58
|
||||
* @Desc: 逻辑结构图
|
||||
*/
|
||||
class LogicalStructure extends Base {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:26:31
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 14:04:20
|
||||
* @Desc: 布局
|
||||
*/
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:49:32
|
||||
* @Desc: 遍历数据计算节点的left、width、height
|
||||
*/
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:59:25
|
||||
* @Desc: 遍历节点树计算节点的top
|
||||
*/
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 10:04:05
|
||||
* @Desc: 调整节点top
|
||||
*/
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:26:03
|
||||
* @Desc: 更新兄弟节点的top
|
||||
*/
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 14:42:48
|
||||
* @Desc: 绘制连线,连接该节点到其子节点
|
||||
*/
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:17:30
|
||||
* @Desc: 直线风格连线
|
||||
*/
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${
|
||||
x1 + s1
|
||||
},${y2} L ${x2},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:34:41
|
||||
* @Desc: 直连风格
|
||||
*/
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:17:43
|
||||
* @Desc: 曲线风格连线
|
||||
*/
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2)
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2)
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:54:26
|
||||
* @Desc: 渲染按钮
|
||||
*/
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
btn.translate(width - translateX, height / 2 - translateY)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-30 08:30:35
|
||||
* @Desc: 创建概要节点
|
||||
*/
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let y1 = top
|
||||
let x2 = right + generalizationLineMargin
|
||||
let y2 = bottom
|
||||
let cx = x1 + 20
|
||||
let cy = y1 + (y2 - y1) / 2
|
||||
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
gLine.plot(path)
|
||||
gNode.left = right + generalizationNodeMargin
|
||||
gNode.top = top + (bottom - top - gNode.height) / 2
|
||||
}
|
||||
}
|
||||
|
||||
export default LogicalStructure
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 逻辑结构图
|
||||
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
btn.translate(
|
||||
width - translateX,
|
||||
height / 2 - translateY + nodeUseLineStyleOffset
|
||||
)
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:25:58
|
||||
* @Desc: 思维导图
|
||||
* 在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可
|
||||
*/
|
||||
// 思维导图
|
||||
|
||||
class MindMap extends Base {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:26:31
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
// 在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 14:04:20
|
||||
* @Desc: 布局
|
||||
*/
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
@@ -41,12 +30,8 @@ class MindMap extends Base {
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:49:32
|
||||
* @Desc: 遍历数据计算节点的left、width、height
|
||||
*/
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
@@ -110,12 +95,8 @@ class MindMap extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:59:25
|
||||
* @Desc: 遍历节点树计算节点的top
|
||||
*/
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
@@ -147,12 +128,8 @@ class MindMap extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 10:04:05
|
||||
* @Desc: 调整节点top
|
||||
*/
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
@@ -174,12 +151,8 @@ class MindMap extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:26:03
|
||||
* @Desc: 更新兄弟节点的top
|
||||
*/
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, leftAddHeight, rightAddHeight) {
|
||||
if (node.parent) {
|
||||
// 过滤出和自己同方向的节点
|
||||
@@ -214,11 +187,8 @@ class MindMap extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 14:42:48
|
||||
* @Desc: 绘制连线,连接该节点到其子节点
|
||||
*/
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
@@ -229,12 +199,8 @@ class MindMap extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:10:47
|
||||
* @Desc: 直线风格连线
|
||||
*/
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
@@ -245,9 +211,14 @@ class MindMap extends Base {
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 = 0
|
||||
let _s = 0
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
if (item.dir === 'left') {
|
||||
_s = -s1
|
||||
x1 = node.layerIndex === 0 ? left : left - expandBtnSize
|
||||
nodeUseLineStyleOffset = -nodeUseLineStyleOffset
|
||||
} else {
|
||||
_s = s1
|
||||
x1 = node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
@@ -255,20 +226,16 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${
|
||||
x1 + _s
|
||||
},${y2} L ${x2},${y2}`
|
||||
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:34:41
|
||||
* @Desc: 直连风格
|
||||
*/
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
@@ -284,18 +251,23 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}`
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
if (item.dir === 'left') {
|
||||
nodeUseLineStylePath = ` L ${item.left},${y2}`
|
||||
} else {
|
||||
nodeUseLineStylePath = ` L ${item.left + item.width},${y2}`
|
||||
}
|
||||
}
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:10:56
|
||||
* @Desc: 曲线风格连线
|
||||
*/
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
@@ -312,34 +284,41 @@ class MindMap extends Base {
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
if (item.dir === 'left') {
|
||||
nodeUseLineStylePath = ` L ${item.left},${y2}`
|
||||
} else {
|
||||
nodeUseLineStylePath = ` L ${item.left + item.width},${y2}`
|
||||
}
|
||||
}
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2)
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2)
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:54:26
|
||||
* @Desc: 渲染按钮
|
||||
*/
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height, expandBtnSize } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
let x = (node.dir === 'left' ? 0 - expandBtnSize : width) - translateX
|
||||
let y = height / 2 - translateY
|
||||
let y = height / 2 - translateY + nodeUseLineStyleOffset
|
||||
btn.translate(x, y)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-30 08:30:35
|
||||
* @Desc: 创建概要节点
|
||||
*/
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let isLeft = node.dir === 'left'
|
||||
let {
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:25:58
|
||||
* @Desc: 组织结构图
|
||||
* 和逻辑结构图基本一样,只是方向变成向下生长,所以先计算节点的top,后计算节点的left、最后调整节点的left即可
|
||||
*/
|
||||
// 组织结构图
|
||||
// 和逻辑结构图基本一样,只是方向变成向下生长,所以先计算节点的top,后计算节点的left、最后调整节点的left即可
|
||||
class OrganizationStructure extends Base {
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-12 22:26:31
|
||||
* @Desc: 构造函数
|
||||
*/
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 14:04:20
|
||||
* @Desc: 布局
|
||||
*/
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
@@ -41,12 +30,8 @@ class OrganizationStructure extends Base {
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:49:32
|
||||
* @Desc: 遍历数据计算节点的left、width、height
|
||||
*/
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
@@ -81,12 +66,8 @@ class OrganizationStructure extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 09:59:25
|
||||
* @Desc: 遍历节点树计算节点的left
|
||||
*/
|
||||
// 遍历节点树计算节点的left
|
||||
|
||||
computedLeftValue() {
|
||||
walk(
|
||||
this.root,
|
||||
@@ -112,12 +93,8 @@ class OrganizationStructure extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-08 10:04:05
|
||||
* @Desc: 调整节点left
|
||||
*/
|
||||
// 调整节点left
|
||||
|
||||
adjustLeftValue() {
|
||||
walk(
|
||||
this.root,
|
||||
@@ -140,12 +117,8 @@ class OrganizationStructure extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 14:26:03
|
||||
* @Desc: 更新兄弟节点的left
|
||||
*/
|
||||
// 更新兄弟节点的left
|
||||
|
||||
updateBrothers(node, addWidth) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
@@ -176,11 +149,8 @@ class OrganizationStructure extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 14:42:48
|
||||
* @Desc: 绘制连线,连接该节点到其子节点
|
||||
*/
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
@@ -189,12 +159,8 @@ class OrganizationStructure extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:34:41
|
||||
* @Desc: 直连风格
|
||||
*/
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
@@ -205,18 +171,18 @@ class OrganizationStructure extends Base {
|
||||
node.children.forEach((item, index) => {
|
||||
let x2 = item.left + item.width / 2
|
||||
let y2 = item.top
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}`
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-30 14:39:07
|
||||
* @Desc: 直线风格连线
|
||||
*/
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
@@ -238,7 +204,11 @@ class OrganizationStructure extends Base {
|
||||
if (x2 > maxx) {
|
||||
maxx = x2
|
||||
}
|
||||
let path = `M ${x2},${y1 + s1} L ${x2},${y2}`
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x2},${y1 + s1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
@@ -261,11 +231,8 @@ class OrganizationStructure extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:54:26
|
||||
* @Desc: 渲染按钮
|
||||
*/
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height, expandBtnSize } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
@@ -275,11 +242,8 @@ class OrganizationStructure extends Base {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-07-30 08:30:35
|
||||
* @Desc: 创建概要节点
|
||||
*/
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
bottom,
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import JSZip from 'jszip'
|
||||
import xmlConvert from 'xml-js'
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-21 14:07:47
|
||||
* @Desc: 解析.xmind文件
|
||||
*/
|
||||
// 解析.xmind文件
|
||||
const parseXmindFile = file => {
|
||||
return new Promise((resolve, reject) => {
|
||||
JSZip.loadAsync(file).then(
|
||||
@@ -37,12 +32,7 @@ const parseXmindFile = file => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-21 18:57:25
|
||||
* @Desc: 转换xmind数据
|
||||
*/
|
||||
// 转换xmind数据
|
||||
const transformXmind = content => {
|
||||
let data = JSON.parse(content)[0]
|
||||
let nodeTree = data.rootTopic
|
||||
@@ -82,12 +72,7 @@ const transformXmind = content => {
|
||||
return newTree
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-09-23 15:51:51
|
||||
* @Desc: 转换旧版xmind数据,xmind8
|
||||
*/
|
||||
// 转换旧版xmind数据,xmind8
|
||||
const transformOldXmind = content => {
|
||||
let data = JSON.parse(content)
|
||||
let elements = data.elements
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:46:10
|
||||
* @Desc: 展开按钮
|
||||
*/
|
||||
// 展开按钮
|
||||
const open = `<svg t="1618141562310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13476" width="200" height="200"><path d="M475.136 327.168v147.968h-147.968v74.24h147.968v147.968h74.24v-147.968h147.968v-74.24h-147.968v-147.968h-74.24z m36.864-222.208c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13477"></path></svg>`
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 19:46:23
|
||||
* @Desc: 收缩按钮
|
||||
*/
|
||||
// 收缩按钮
|
||||
const close = `<svg t="1618141589243" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13611" width="200" height="200"><path d="M512 105.472c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13612"></path><path d="M252.928 474.624h518.144v74.24h-518.144z" p-id="13613"></path></svg>`
|
||||
|
||||
export default {
|
||||
|
||||
@@ -278,11 +278,7 @@ export const nodeIconList = [
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-23 22:36:56
|
||||
* @Desc: 获取nodeIconList icon内容
|
||||
*/
|
||||
// 获取nodeIconList icon内容
|
||||
const getNodeIconListIcon = name => {
|
||||
let arr = name.split('_')
|
||||
let typeData = nodeIconList.find(item => {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 天空蓝
|
||||
*/
|
||||
// 天空蓝
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(115, 161, 191)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 脑残粉
|
||||
*/
|
||||
// 脑残粉
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(191, 115, 148)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 脑图经典
|
||||
*/
|
||||
// 脑图经典
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: '#fff',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 经典2
|
||||
*/
|
||||
// 经典2
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(51, 51, 51)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 经典3
|
||||
*/
|
||||
// 经典3
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(94, 202, 110)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 经典4
|
||||
*/
|
||||
// 经典4
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(30, 53, 86)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 经典蓝
|
||||
*/
|
||||
// 经典蓝
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(51, 51, 51)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 经典绿
|
||||
*/
|
||||
// 经典绿
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(123, 199, 120)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 暗色
|
||||
*/
|
||||
// 暗色
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(17, 68, 23)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 暗色2
|
||||
*/
|
||||
// 暗色2
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(75, 81, 78)',
|
||||
|
||||
@@ -1,144 +1,142 @@
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 10:19:55
|
||||
* @Desc: 默认主题
|
||||
*/
|
||||
export default {
|
||||
// 节点内边距
|
||||
paddingX: 15,
|
||||
paddingY: 5,
|
||||
// 图片显示的最大宽度
|
||||
imgMaxWidth: 100,
|
||||
// 图片显示的最大高度
|
||||
imgMaxHeight: 100,
|
||||
// icon的大小
|
||||
iconSize: 20,
|
||||
// 连线的粗细
|
||||
lineWidth: 1,
|
||||
// 连线的颜色
|
||||
lineColor: '#549688',
|
||||
// 连线样式
|
||||
lineDasharray: 'none',
|
||||
// 连线风格
|
||||
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线(curve)、直线(straight)、直连(direct)
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 1,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#549688',
|
||||
// 概要曲线距节点的距离
|
||||
generalizationLineMargin: 0,
|
||||
// 概要节点距节点的距离
|
||||
generalizationNodeMargin: 20,
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
backgroundImage: 'none',
|
||||
// 背景重复
|
||||
backgroundRepeat: 'no-repeat',
|
||||
// 根节点样式
|
||||
root: {
|
||||
shape: 'rectangle',
|
||||
fillColor: '#549688',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
shape: 'rectangle',
|
||||
marginX: 50,
|
||||
marginY: 0,
|
||||
fillColor: 'transparent',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#6a6d6c',
|
||||
fontSize: 14,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderRadius: 5,
|
||||
borderDasharray: 'none',
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 支持激活样式的属性
|
||||
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
|
||||
export const supportActiveStyle = [
|
||||
'fillColor',
|
||||
'color',
|
||||
'fontWeight',
|
||||
'fontStyle',
|
||||
'borderColor',
|
||||
'borderWidth',
|
||||
'borderDasharray',
|
||||
'borderRadius',
|
||||
'textDecoration'
|
||||
]
|
||||
|
||||
export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']
|
||||
// 默认主题
|
||||
|
||||
export default {
|
||||
// 节点内边距
|
||||
paddingX: 15,
|
||||
paddingY: 5,
|
||||
// 图片显示的最大宽度
|
||||
imgMaxWidth: 100,
|
||||
// 图片显示的最大高度
|
||||
imgMaxHeight: 100,
|
||||
// icon的大小
|
||||
iconSize: 20,
|
||||
// 连线的粗细
|
||||
lineWidth: 1,
|
||||
// 连线的颜色
|
||||
lineColor: '#549688',
|
||||
// 连线样式
|
||||
lineDasharray: 'none',
|
||||
// 连线风格
|
||||
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线(curve)、直线(straight)、直连(direct)
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 1,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#549688',
|
||||
// 概要曲线距节点的距离
|
||||
generalizationLineMargin: 0,
|
||||
// 概要节点距节点的距离
|
||||
generalizationNodeMargin: 20,
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
backgroundImage: 'none',
|
||||
// 背景重复
|
||||
backgroundRepeat: 'no-repeat',
|
||||
// 节点使用横线样式
|
||||
nodeUseLineStyle: false,
|
||||
// 根节点样式
|
||||
root: {
|
||||
shape: 'rectangle',
|
||||
fillColor: '#549688',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
shape: 'rectangle',
|
||||
marginX: 50,
|
||||
marginY: 0,
|
||||
fillColor: 'transparent',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#6a6d6c',
|
||||
fontSize: 14,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderRadius: 5,
|
||||
borderDasharray: 'none',
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 支持激活样式的属性
|
||||
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
|
||||
export const supportActiveStyle = [
|
||||
'fillColor',
|
||||
'color',
|
||||
'fontWeight',
|
||||
'fontStyle',
|
||||
'borderColor',
|
||||
'borderWidth',
|
||||
'borderDasharray',
|
||||
'borderRadius',
|
||||
'textDecoration'
|
||||
]
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 泥土黄
|
||||
*/
|
||||
// 泥土黄
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(191, 147, 115)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 清新绿
|
||||
*/
|
||||
// 清新绿
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: '#333',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 清新红
|
||||
*/
|
||||
// 清新红
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(191, 115, 115)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 金色vip
|
||||
*/
|
||||
// 金色vip
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(51, 56, 62)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 绿叶
|
||||
*/
|
||||
// 绿叶
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(40, 193, 84)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 小黄人
|
||||
*/
|
||||
// 小黄人
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(51, 51, 51)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 薄荷
|
||||
*/
|
||||
// 薄荷
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(104, 204, 202)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 粉红葡萄
|
||||
*/
|
||||
// 粉红葡萄
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(166, 101, 106)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 浪漫紫
|
||||
*/
|
||||
// 浪漫紫
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(123, 115, 191)',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 天清绿
|
||||
*/
|
||||
// 天清绿
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: '#fff',
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-04-11 15:22:18
|
||||
* @Desc: 活力橙
|
||||
*/
|
||||
// 活力橙
|
||||
export default merge(defaultTheme, {
|
||||
// 连线的颜色
|
||||
lineColor: 'rgb(254, 146, 0)',
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-24 21:42:07
|
||||
* @Desc: 标签颜色列表
|
||||
*/
|
||||
// 标签颜色列表
|
||||
export const tagColorList = [
|
||||
{
|
||||
color: 'rgb(77, 65, 0)',
|
||||
@@ -26,12 +22,7 @@ export const tagColorList = [
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-07-13 15:56:28
|
||||
* @Desc: 布局结构列表
|
||||
*/
|
||||
// 布局结构列表
|
||||
export const layoutList = [
|
||||
{
|
||||
name: '逻辑结构图',
|
||||
@@ -61,11 +52,7 @@ export const layoutValueList = [
|
||||
'organizationStructure'
|
||||
]
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-24 22:58:42
|
||||
* @Desc: 主题列表
|
||||
*/
|
||||
// 主题列表
|
||||
export const themeList = [
|
||||
{
|
||||
name: '默认',
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-06 14:13:17
|
||||
* @Desc: 深度优先遍历树
|
||||
*/
|
||||
// 深度优先遍历树
|
||||
export const walk = (
|
||||
root,
|
||||
parent,
|
||||
@@ -34,12 +29,7 @@ export const walk = (
|
||||
afterCallback && afterCallback(root, parent, isRoot, layerIndex, index)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-07 18:47:20
|
||||
* @Desc: 广度优先遍历树
|
||||
*/
|
||||
// 广度优先遍历树
|
||||
export const bfsWalk = (root, callback) => {
|
||||
callback(root)
|
||||
let stack = [root]
|
||||
@@ -60,12 +50,7 @@ export const bfsWalk = (root, callback) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-09 10:44:54
|
||||
* @Desc: 缩放图片尺寸
|
||||
*/
|
||||
// 缩放图片尺寸
|
||||
export const resizeImgSize = (width, height, maxWidth, maxHeight) => {
|
||||
let nRatio = width / height
|
||||
let arr = []
|
||||
@@ -98,12 +83,7 @@ export const resizeImgSize = (width, height, maxWidth, maxHeight) => {
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-04-09 10:18:42
|
||||
* @Desc: 缩放图片
|
||||
*/
|
||||
// 缩放图片
|
||||
export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let img = new Image()
|
||||
@@ -123,11 +103,7 @@ export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 12:26:56
|
||||
* @Desc: 从头html结构字符串里获取带换行符的字符串
|
||||
*/
|
||||
// 从头html结构字符串里获取带换行符的字符串
|
||||
export const getStrWithBrFromHtml = str => {
|
||||
str = str.replace(/<br>/gim, '\n')
|
||||
let el = document.createElement('div')
|
||||
@@ -136,11 +112,7 @@ export const getStrWithBrFromHtml = str => {
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 14:45:39
|
||||
* @Desc: 极简的深拷贝
|
||||
*/
|
||||
// 极简的深拷贝
|
||||
export const simpleDeepClone = data => {
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(data))
|
||||
@@ -149,11 +121,7 @@ export const simpleDeepClone = data => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 14:40:11
|
||||
* @Desc: 复制渲染树数据
|
||||
*/
|
||||
// 复制渲染树数据
|
||||
export const copyRenderTree = (tree, root) => {
|
||||
tree.data = simpleDeepClone(root.data)
|
||||
tree.children = []
|
||||
@@ -165,11 +133,7 @@ export const copyRenderTree = (tree, root) => {
|
||||
return tree
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-04 14:40:11
|
||||
* @Desc: 复制节点树数据
|
||||
*/
|
||||
// 复制节点树数据
|
||||
export const copyNodeTree = (tree, root, removeActiveState = false) => {
|
||||
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
|
||||
if (removeActiveState) {
|
||||
@@ -192,11 +156,7 @@ export const copyNodeTree = (tree, root, removeActiveState = false) => {
|
||||
return tree
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 09:08:43
|
||||
* @Desc: 图片转成dataURL
|
||||
*/
|
||||
// 图片转成dataURL
|
||||
export const imgToDataUrl = src => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
@@ -222,11 +182,7 @@ export const imgToDataUrl = src => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-04 16:20:06
|
||||
* @Desc: 下载文件
|
||||
*/
|
||||
// 下载文件
|
||||
export const downloadFile = (file, fileName) => {
|
||||
let a = document.createElement('a')
|
||||
a.href = file
|
||||
@@ -234,11 +190,7 @@ export const downloadFile = (file, fileName) => {
|
||||
a.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-11 10:36:47
|
||||
* @Desc: 节流函数
|
||||
*/
|
||||
// 节流函数
|
||||
export const throttle = (fn, time = 300, ctx) => {
|
||||
let timer = null
|
||||
return () => {
|
||||
@@ -252,12 +204,7 @@ export const throttle = (fn, time = 300, ctx) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2021-07-12 10:27:36
|
||||
* @Desc: 异步执行任务队列
|
||||
*/
|
||||
// 异步执行任务队列
|
||||
export const asyncRun = (taskList, callback = () => {}) => {
|
||||
let index = 0
|
||||
let len = taskList.length
|
||||
|
||||
@@ -6,4 +6,6 @@ public
|
||||
*.md
|
||||
.eslintrc.js
|
||||
.prettierignore
|
||||
.prettierrc
|
||||
.prettierrc
|
||||
package-lock.json
|
||||
package.json
|
||||
29069
web/package-lock.json
generated
Normal file
29069
web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
"build": "vue-cli-service build && node ../copy.js",
|
||||
"lint": "vue-cli-service lint",
|
||||
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/index.js --dest ../simple-mind-map/dist",
|
||||
"format": "prettier --write src/**"
|
||||
"format": "prettier --write src/* src/*/* src/*/*/* src/*/*/*/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
@@ -15,6 +15,7 @@
|
||||
"element-ui": "^2.15.1",
|
||||
"v-viewer": "^1.6.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.27.2",
|
||||
"vue-router": "^3.5.1",
|
||||
"vuex": "^3.6.2",
|
||||
"xlsx": "^0.18.5"
|
||||
|
||||
@@ -3,6 +3,8 @@ import { simpleDeepClone } from 'simple-mind-map/src/utils/index'
|
||||
import Vue from 'vue'
|
||||
|
||||
const SIMPLE_MIND_MAP_DATA = 'SIMPLE_MIND_MAP_DATA'
|
||||
const SIMPLE_MIND_MAP_LANG = 'SIMPLE_MIND_MAP_LANG'
|
||||
const SIMPLE_MIND_MAP_LOCAL_CONFIG = 'SIMPLE_MIND_MAP_LOCAL_CONFIG'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -75,3 +77,52 @@ export const storeConfig = config => {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-11-05 14:36:50
|
||||
* @Desc: 存储语言
|
||||
*/
|
||||
export const storeLang = lang => {
|
||||
localStorage.setItem(SIMPLE_MIND_MAP_LANG, lang)
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林
|
||||
* @Date: 2022-11-05 14:37:36
|
||||
* @Desc: 获取存储的语言
|
||||
*/
|
||||
export const getLang = () => {
|
||||
let lang = localStorage.getItem(SIMPLE_MIND_MAP_LANG)
|
||||
if (lang) {
|
||||
return lang
|
||||
}
|
||||
storeLang('zh')
|
||||
return 'zh'
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 18:57:31
|
||||
* @Desc: 存储本地配置
|
||||
*/
|
||||
export const storeLocalConfig = config => {
|
||||
localStorage.setItem(SIMPLE_MIND_MAP_LOCAL_CONFIG, JSON.stringify(config))
|
||||
}
|
||||
|
||||
/**
|
||||
* javascript comment
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 18:57:37
|
||||
* @Desc: 获取本地配置
|
||||
*/
|
||||
export const getLocalConfig = () => {
|
||||
let config = localStorage.getItem(SIMPLE_MIND_MAP_LOCAL_CONFIG)
|
||||
if (config) {
|
||||
return JSON.parse(config)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: 'iconfont logo';
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix')
|
||||
format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834')
|
||||
format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834')
|
||||
format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont')
|
||||
format('svg');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: 'iconfont logo';
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@@ -52,6 +48,7 @@
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
@@ -218,35 +215,35 @@
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown > p,
|
||||
.markdown > blockquote,
|
||||
.markdown > .highlight,
|
||||
.markdown > ol,
|
||||
.markdown > ul {
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul > li {
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown > ul li,
|
||||
.markdown blockquote ul > li {
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown > ul li p,
|
||||
.markdown > ol li p {
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol > li {
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown > ol li,
|
||||
.markdown blockquote ol > li {
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
@@ -263,7 +260,7 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown > table {
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
@@ -272,21 +269,21 @@
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown > table th {
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown > table th,
|
||||
.markdown > table td {
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown > table th {
|
||||
background: #f7f7f7;
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
@@ -321,11 +318,12 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown > br,
|
||||
.markdown > p > br {
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
@@ -401,8 +399,8 @@ https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javasc
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
@@ -424,45 +422,46 @@ pre[class*='language-'] {
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*='language-']::-moz-selection,
|
||||
pre[class*='language-'] ::-moz-selection,
|
||||
code[class*='language-']::-moz-selection,
|
||||
code[class*='language-'] ::-moz-selection {
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*='language-']::selection,
|
||||
pre[class*='language-'] ::selection,
|
||||
code[class*='language-']::selection,
|
||||
code[class*='language-'] ::selection {
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*='language-'] {
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: 0.5em 0;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*='language-'] {
|
||||
padding: 0.1em;
|
||||
border-radius: 0.3em;
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@@ -478,7 +477,7 @@ pre[class*='language-'] {
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: 0.7;
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
@@ -506,7 +505,7 @@ pre[class*='language-'] {
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, 0.5);
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
@@ -517,7 +516,7 @@ pre[class*='language-'] {
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #dd4a68;
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,186 +1,195 @@
|
||||
@font-face {
|
||||
font-family: 'iconfont'; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1664005697217') format('woff2'),
|
||||
url('iconfont.woff?t=1664005697217') format('woff'),
|
||||
url('iconfont.ttf?t=1664005697217') format('truetype');
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1668512547595') format('woff2'),
|
||||
url('iconfont.woff?t=1668512547595') format('woff'),
|
||||
url('iconfont.ttf?t=1668512547595') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: 'iconfont' !important;
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconchoose1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.iconzhuti:before {
|
||||
content: "\e7aa";
|
||||
}
|
||||
|
||||
.icondaochu1:before {
|
||||
content: '\e63e';
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.iconlingcunwei:before {
|
||||
content: '\e657';
|
||||
content: "\e657";
|
||||
}
|
||||
|
||||
.iconexport:before {
|
||||
content: '\e642';
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icondakai:before {
|
||||
content: '\ebdf';
|
||||
content: "\ebdf";
|
||||
}
|
||||
|
||||
.iconxinjian:before {
|
||||
content: '\e64e';
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.iconjianqie:before {
|
||||
content: '\e601';
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.iconzhengli:before {
|
||||
content: '\e83b';
|
||||
content: "\e83b";
|
||||
}
|
||||
|
||||
.iconfuzhi:before {
|
||||
content: '\e604';
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.iconniantie:before {
|
||||
content: '\e63f';
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.iconshangyi:before {
|
||||
content: '\e6be';
|
||||
content: "\e6be";
|
||||
}
|
||||
|
||||
.iconxiayi:before {
|
||||
content: '\e6bf';
|
||||
content: "\e6bf";
|
||||
}
|
||||
|
||||
.icongaikuozonglan:before {
|
||||
content: '\e609';
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.iconquanxuan:before {
|
||||
content: '\f199';
|
||||
content: "\f199";
|
||||
}
|
||||
|
||||
.icondaoru:before {
|
||||
content: '\e6a3';
|
||||
content: "\e6a3";
|
||||
}
|
||||
|
||||
.iconhoutui-shi:before {
|
||||
content: '\e656';
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.iconqianjin1:before {
|
||||
content: '\e654';
|
||||
content: "\e654";
|
||||
}
|
||||
|
||||
.iconwithdraw:before {
|
||||
content: '\e603';
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.iconqianjin:before {
|
||||
content: '\e600';
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.iconhuifumoren:before {
|
||||
content: '\e60e';
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.iconhuanhang:before {
|
||||
content: '\e61e';
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.iconsuoxiao:before {
|
||||
content: '\ec13';
|
||||
content: "\ec13";
|
||||
}
|
||||
|
||||
.iconbianji:before {
|
||||
content: '\e626';
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.iconfangda:before {
|
||||
content: '\e663';
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.iconquanping1:before {
|
||||
content: '\e664';
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icondingwei:before {
|
||||
content: '\e616';
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icondaohang:before {
|
||||
content: '\e611';
|
||||
content: "\e611";
|
||||
}
|
||||
|
||||
.iconjianpan:before {
|
||||
content: '\e64d';
|
||||
content: "\e64d";
|
||||
}
|
||||
|
||||
.iconquanping:before {
|
||||
content: '\e602';
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icondaochu:before {
|
||||
content: '\e63d';
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.iconbiaoqian:before {
|
||||
content: '\e63c';
|
||||
content: "\e63c";
|
||||
}
|
||||
|
||||
.iconflow-Mark:before {
|
||||
content: '\e65b';
|
||||
content: "\e65b";
|
||||
}
|
||||
|
||||
.iconchaolianjie:before {
|
||||
content: '\e6f4';
|
||||
content: "\e6f4";
|
||||
}
|
||||
|
||||
.iconjingzi:before {
|
||||
content: '\e610';
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.iconxiaolian:before {
|
||||
content: '\e60f';
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.iconimage:before {
|
||||
content: '\e629';
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.iconjiegou:before {
|
||||
content: '\e61d';
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.iconyangshi:before {
|
||||
content: '\e631';
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.iconfuhao-dagangshu:before {
|
||||
content: '\e71f';
|
||||
content: "\e71f";
|
||||
}
|
||||
|
||||
.icontianjiazijiedian:before {
|
||||
content: '\e622';
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.iconjiedian:before {
|
||||
content: '\e655';
|
||||
content: "\e655";
|
||||
}
|
||||
|
||||
.iconshanchu:before {
|
||||
content: '\e696';
|
||||
content: "\e696";
|
||||
}
|
||||
|
||||
.iconzhankai:before {
|
||||
content: '\e64c';
|
||||
content: "\e64c";
|
||||
}
|
||||
|
||||
.iconzhankai1:before {
|
||||
content: '\e673';
|
||||
content: "\e673";
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,20 @@
|
||||
"css_prefix_text": "icon",
|
||||
"description": "思维导图",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "1009019",
|
||||
"name": "选择",
|
||||
"font_class": "choose1",
|
||||
"unicode": "e6c5",
|
||||
"unicode_decimal": 59077
|
||||
},
|
||||
{
|
||||
"icon_id": "493507",
|
||||
"name": "主题",
|
||||
"font_class": "zhuti",
|
||||
"unicode": "e7aa",
|
||||
"unicode_decimal": 59306
|
||||
},
|
||||
{
|
||||
"icon_id": "1305460",
|
||||
"name": "导出",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
355
web/src/config/en.js
Normal file
355
web/src/config/en.js
Normal file
@@ -0,0 +1,355 @@
|
||||
// 字体列表
|
||||
export const fontFamilyList = [
|
||||
{
|
||||
name: 'Song Ti',
|
||||
value: '宋体, SimSun, Songti SC'
|
||||
},
|
||||
{
|
||||
name: 'Microsoft Yahei',
|
||||
value: '微软雅黑, Microsoft YaHei'
|
||||
},
|
||||
{
|
||||
name: 'Italics',
|
||||
value: '楷体, 楷体_GB2312, SimKai, STKaiti'
|
||||
},
|
||||
{
|
||||
name: 'Boldface',
|
||||
value: '黑体, SimHei, Heiti SC'
|
||||
},
|
||||
{
|
||||
name: 'Official script',
|
||||
value: '隶书, SimLi'
|
||||
},
|
||||
{
|
||||
name: 'Andale Mono',
|
||||
value: 'andale mono'
|
||||
},
|
||||
{
|
||||
name: 'Arial',
|
||||
value: 'arial, helvetica, sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'arialBlack',
|
||||
value: 'arial black, avant garde'
|
||||
},
|
||||
{
|
||||
name: 'Comic Sans Ms',
|
||||
value: 'comic sans ms'
|
||||
},
|
||||
{
|
||||
name: 'Impact',
|
||||
value: 'impact, chicago'
|
||||
},
|
||||
{
|
||||
name: 'Times New Roman',
|
||||
value: 'times new roman'
|
||||
},
|
||||
{
|
||||
name: 'Sans-Serif',
|
||||
value: 'sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'serif',
|
||||
value: 'serif'
|
||||
}
|
||||
]
|
||||
|
||||
// 边框样式
|
||||
export const borderDasharrayList = [
|
||||
{
|
||||
name: 'Solid',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
name: 'Dotted1',
|
||||
value: '5,5'
|
||||
},
|
||||
{
|
||||
name: 'Dotted2',
|
||||
value: '10,10'
|
||||
},
|
||||
{
|
||||
name: 'Dotted3',
|
||||
value: '20,10,5,5,5,10'
|
||||
},
|
||||
{
|
||||
name: 'Dotted4',
|
||||
value: '5, 5, 1, 5'
|
||||
},
|
||||
{
|
||||
name: 'Dotted5',
|
||||
value: '15, 10, 5, 10, 15'
|
||||
},
|
||||
{
|
||||
name: 'Dotted6',
|
||||
value: '1, 5'
|
||||
}
|
||||
]
|
||||
|
||||
// 连线风格
|
||||
export const lineStyleList = [
|
||||
{
|
||||
name: 'Straight',
|
||||
value: 'straight'
|
||||
},
|
||||
{
|
||||
name: 'Curve',
|
||||
value: 'curve'
|
||||
},
|
||||
{
|
||||
name: 'Direct',
|
||||
value: 'direct'
|
||||
}
|
||||
]
|
||||
|
||||
// 图片重复方式
|
||||
export const backgroundRepeatList = [
|
||||
{
|
||||
name: 'No repeat',
|
||||
value: 'no-repeat'
|
||||
},
|
||||
{
|
||||
name: 'Repeat',
|
||||
value: 'repeat'
|
||||
},
|
||||
{
|
||||
name: 'Repeat-x',
|
||||
value: 'repeat-x'
|
||||
},
|
||||
{
|
||||
name: 'Repeat-y',
|
||||
value: 'repeat-y'
|
||||
}
|
||||
]
|
||||
|
||||
// 背景图片定位
|
||||
export const backgroundPositionList = [
|
||||
{
|
||||
name: 'Default',
|
||||
value: '0% 0%'
|
||||
},
|
||||
{
|
||||
name: 'Left top',
|
||||
value: 'left top'
|
||||
},
|
||||
{
|
||||
name: 'Left center',
|
||||
value: 'left center'
|
||||
},
|
||||
{
|
||||
name: 'Left bottom',
|
||||
value: 'left bottom'
|
||||
},
|
||||
{
|
||||
name: 'Right top',
|
||||
value: 'right top'
|
||||
},
|
||||
{
|
||||
name: 'Right center',
|
||||
value: 'right center'
|
||||
},
|
||||
{
|
||||
name: 'Right bottom',
|
||||
value: 'right bottom'
|
||||
},
|
||||
{
|
||||
name: 'Center top',
|
||||
value: 'center top'
|
||||
},
|
||||
{
|
||||
name: 'Center center',
|
||||
value: 'center center'
|
||||
},
|
||||
{
|
||||
name: 'Center bottom',
|
||||
value: 'center bottom'
|
||||
}
|
||||
]
|
||||
|
||||
// 快捷键列表
|
||||
export const shortcutKeyList = [
|
||||
{
|
||||
type: 'Node operation',
|
||||
list: [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: 'Inert child node',
|
||||
value: 'Tab'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
name: 'Insert sibling node',
|
||||
value: 'Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconshangyi',
|
||||
name: 'Move up node',
|
||||
value: 'Ctrl + ↑'
|
||||
},
|
||||
{
|
||||
icon: 'iconxiayi',
|
||||
name: 'Move down node',
|
||||
value: 'Ctrl + ↓'
|
||||
},
|
||||
{
|
||||
icon: 'icongaikuozonglan',
|
||||
name: 'Insert summary',
|
||||
value: 'Ctrl + S'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhankai',
|
||||
name: 'Expand/UnExpand node',
|
||||
value: '/'
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: 'Delete node',
|
||||
value: 'Delete | Backspace'
|
||||
},
|
||||
{
|
||||
icon: 'iconfuzhi',
|
||||
name: 'Copy node',
|
||||
value: 'Ctrl + C'
|
||||
},
|
||||
{
|
||||
icon: 'iconjianqie',
|
||||
name: 'Cut node',
|
||||
value: 'Ctrl + X'
|
||||
},
|
||||
{
|
||||
icon: 'iconniantie',
|
||||
name: 'Paste node',
|
||||
value: 'Ctrl + V'
|
||||
},
|
||||
{
|
||||
icon: 'iconbianji',
|
||||
name: 'Edit node',
|
||||
value: 'F2'
|
||||
},
|
||||
{
|
||||
icon: 'iconhuanhang',
|
||||
name: 'Text Wrap',
|
||||
value: 'Shift + Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconhoutui-shi',
|
||||
name: 'Undo',
|
||||
value: 'Ctrl + Z'
|
||||
},
|
||||
{
|
||||
icon: 'iconqianjin1',
|
||||
name: 'Redo',
|
||||
value: 'Ctrl + Y'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: 'Select All',
|
||||
value: 'Ctrl + A'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: 'Multiple choice',
|
||||
value: 'Right click / Ctrl + Left click'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhengli',
|
||||
name: 'Arrange layout',
|
||||
value: 'Ctrl + L'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Canvas operation',
|
||||
list: [
|
||||
{
|
||||
icon: 'iconfangda',
|
||||
name: 'Zoom in',
|
||||
value: 'Ctrl + +'
|
||||
},
|
||||
{
|
||||
icon: 'iconsuoxiao',
|
||||
name: 'Zoom out',
|
||||
value: 'Ctrl + -'
|
||||
},
|
||||
{
|
||||
icon: 'icondingwei',
|
||||
name: 'Reset',
|
||||
value: 'Ctrl + Enter'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 形状列表
|
||||
export const shapeList = [
|
||||
{
|
||||
name: 'Rectangle',
|
||||
value: 'rectangle'
|
||||
},
|
||||
{
|
||||
name: 'Diamond',
|
||||
value: 'diamond'
|
||||
},
|
||||
{
|
||||
name: 'Parallelogram',
|
||||
value: 'parallelogram'
|
||||
},
|
||||
{
|
||||
name: 'Rounded rectangle',
|
||||
value: 'roundedRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Octagonal rectangle',
|
||||
value: 'octagonalRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Outer triangular rectangle',
|
||||
value: 'outerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Inner triangular rectangle',
|
||||
value: 'innerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Ellipse',
|
||||
value: 'ellipse'
|
||||
},
|
||||
{
|
||||
name: 'Circle',
|
||||
value: 'circle'
|
||||
}
|
||||
]
|
||||
|
||||
// 侧边栏列表
|
||||
export const sidebarTriggerList = [
|
||||
{
|
||||
name: 'Node style',
|
||||
value: 'nodeStyle',
|
||||
icon: 'iconzhuti'
|
||||
},
|
||||
{
|
||||
name: 'Base style',
|
||||
value: 'baseStyle',
|
||||
icon: 'iconyangshi'
|
||||
},
|
||||
{
|
||||
name: 'Theme',
|
||||
value: 'theme',
|
||||
icon: 'iconjingzi'
|
||||
},
|
||||
{
|
||||
name: 'Structure',
|
||||
value: 'structure',
|
||||
icon: 'iconjiegou'
|
||||
},
|
||||
{
|
||||
name: 'Outline',
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: 'ShortcutKey',
|
||||
value: 'shortcutKey',
|
||||
icon: 'iconjianpan'
|
||||
}
|
||||
]
|
||||
@@ -1,381 +1,87 @@
|
||||
// 字体列表
|
||||
export const fontFamilyList = [
|
||||
{
|
||||
name: '宋体',
|
||||
value: '宋体, SimSun, Songti SC'
|
||||
},
|
||||
{
|
||||
name: '微软雅黑',
|
||||
value: '微软雅黑, Microsoft YaHei'
|
||||
},
|
||||
{
|
||||
name: '楷体',
|
||||
value: '楷体, 楷体_GB2312, SimKai, STKaiti'
|
||||
},
|
||||
{
|
||||
name: '黑体',
|
||||
value: '黑体, SimHei, Heiti SC'
|
||||
},
|
||||
{
|
||||
name: '隶书',
|
||||
value: '隶书, SimLi'
|
||||
},
|
||||
{
|
||||
name: 'Andale Mono',
|
||||
value: 'andale mono'
|
||||
},
|
||||
{
|
||||
name: 'Arial',
|
||||
value: 'arial, helvetica, sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'arialBlack',
|
||||
value: 'arial black, avant garde'
|
||||
},
|
||||
{
|
||||
name: 'Comic Sans Ms',
|
||||
value: 'comic sans ms'
|
||||
},
|
||||
{
|
||||
name: 'Impact',
|
||||
value: 'impact, chicago'
|
||||
},
|
||||
{
|
||||
name: 'Times New Roman',
|
||||
value: 'times new roman'
|
||||
},
|
||||
{
|
||||
name: 'Sans-Serif',
|
||||
value: 'sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'serif',
|
||||
value: 'serif'
|
||||
}
|
||||
]
|
||||
import {
|
||||
fontSizeList,
|
||||
lineHeightList,
|
||||
colorList,
|
||||
borderWidthList,
|
||||
borderRadiusList,
|
||||
lineWidthList,
|
||||
store,
|
||||
langList,
|
||||
fontFamilyList as fontFamilyListZh,
|
||||
borderDasharrayList as borderDasharrayListZh,
|
||||
lineStyleList as lineStyleListZh,
|
||||
backgroundRepeatList as backgroundRepeatListZh,
|
||||
backgroundPositionList as backgroundPositionListZh,
|
||||
shortcutKeyList as shortcutKeyListZh,
|
||||
shapeList as shapeListZh,
|
||||
sidebarTriggerList as sidebarTriggerListZh
|
||||
} from './zh'
|
||||
import {
|
||||
fontFamilyList as fontFamilyListEn,
|
||||
borderDasharrayList as borderDasharrayListEn,
|
||||
lineStyleList as lineStyleListEn,
|
||||
backgroundRepeatList as backgroundRepeatListEn,
|
||||
backgroundPositionList as backgroundPositionListEn,
|
||||
shortcutKeyList as shortcutKeyListEn,
|
||||
shapeList as shapeListEn,
|
||||
sidebarTriggerList as sidebarTriggerListEn
|
||||
} from './en'
|
||||
|
||||
// 字号
|
||||
export const fontSizeList = [10, 12, 16, 18, 24, 32, 48]
|
||||
|
||||
// 行高
|
||||
export const lineHeightList = [1, 1.5, 2, 2.5, 3]
|
||||
|
||||
// 颜色
|
||||
export const colorList = [
|
||||
'#4D4D4D',
|
||||
'#999999',
|
||||
'#FFFFFF',
|
||||
'#F44E3B',
|
||||
'#FE9200',
|
||||
'#FCDC00',
|
||||
'#DBDF00',
|
||||
'#A4DD00',
|
||||
'#68CCCA',
|
||||
'#73D8FF',
|
||||
'#AEA1FF',
|
||||
'#FDA1FF',
|
||||
'#333333',
|
||||
'#808080',
|
||||
'#cccccc',
|
||||
'#D33115',
|
||||
'#E27300',
|
||||
'#FCC400',
|
||||
'#B0BC00',
|
||||
'#68BC00',
|
||||
'#16A5A5',
|
||||
'#009CE0',
|
||||
'#7B64FF',
|
||||
'#FA28FF',
|
||||
'#000000',
|
||||
'#666666',
|
||||
'#B3B3B3',
|
||||
'#9F0500',
|
||||
'#C45100',
|
||||
'#FB9E00',
|
||||
'#808900',
|
||||
'#194D33',
|
||||
'#0C797D',
|
||||
'#0062B1',
|
||||
'#653294',
|
||||
'#AB149E'
|
||||
]
|
||||
|
||||
// 边框宽度
|
||||
export const borderWidthList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 边框样式
|
||||
export const borderDasharrayList = [
|
||||
{
|
||||
name: '实线',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
name: '虚线1',
|
||||
value: '5,5'
|
||||
},
|
||||
{
|
||||
name: '虚线2',
|
||||
value: '10,10'
|
||||
},
|
||||
{
|
||||
name: '虚线3',
|
||||
value: '20,10,5,5,5,10'
|
||||
},
|
||||
{
|
||||
name: '虚线4',
|
||||
value: '5, 5, 1, 5'
|
||||
},
|
||||
{
|
||||
name: '虚线5',
|
||||
value: '15, 10, 5, 10, 15'
|
||||
},
|
||||
{
|
||||
name: '虚线6',
|
||||
value: '1, 5'
|
||||
}
|
||||
]
|
||||
|
||||
// 圆角
|
||||
export const borderRadiusList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 线宽
|
||||
export const lineWidthList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 连线风格
|
||||
export const lineStyleList = [
|
||||
{
|
||||
name: '直线',
|
||||
value: 'straight'
|
||||
},
|
||||
{
|
||||
name: '曲线',
|
||||
value: 'curve'
|
||||
},
|
||||
{
|
||||
name: '直连',
|
||||
value: 'direct'
|
||||
}
|
||||
]
|
||||
|
||||
// 图片重复方式
|
||||
export const backgroundRepeatList = [
|
||||
{
|
||||
name: '不重复',
|
||||
value: 'no-repeat'
|
||||
},
|
||||
{
|
||||
name: '重复',
|
||||
value: 'repeat'
|
||||
},
|
||||
{
|
||||
name: '水平方向重复',
|
||||
value: 'repeat-x'
|
||||
},
|
||||
{
|
||||
name: '垂直方向重复',
|
||||
value: 'repeat-y'
|
||||
}
|
||||
]
|
||||
|
||||
// 背景图片定位
|
||||
export const backgroundPositionList = [
|
||||
{
|
||||
name: '默认',
|
||||
value: '0% 0%'
|
||||
},
|
||||
{
|
||||
name: '左上',
|
||||
value: 'left top'
|
||||
},
|
||||
{
|
||||
name: '左中',
|
||||
value: 'left center'
|
||||
},
|
||||
{
|
||||
name: '左下',
|
||||
value: 'left bottom'
|
||||
},
|
||||
{
|
||||
name: '右上',
|
||||
value: 'right top'
|
||||
},
|
||||
{
|
||||
name: '右中',
|
||||
value: 'right center'
|
||||
},
|
||||
{
|
||||
name: '右下',
|
||||
value: 'right bottom'
|
||||
},
|
||||
{
|
||||
name: '中上',
|
||||
value: 'center top'
|
||||
},
|
||||
{
|
||||
name: '居中',
|
||||
value: 'center center'
|
||||
},
|
||||
{
|
||||
name: '中下',
|
||||
value: 'center bottom'
|
||||
}
|
||||
]
|
||||
|
||||
// 数据存储
|
||||
export const store = {
|
||||
sidebarZIndex: 1 //侧边栏zIndex
|
||||
const fontFamilyList = {
|
||||
zh: fontFamilyListZh,
|
||||
en: fontFamilyListEn
|
||||
}
|
||||
|
||||
// 快捷键列表
|
||||
export const shortcutKeyList = [
|
||||
{
|
||||
type: '节点操作',
|
||||
list: [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: '插入下级节点',
|
||||
value: 'Tab'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
name: '插入同级节点',
|
||||
value: 'Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconshangyi',
|
||||
name: '上移节点',
|
||||
value: 'Ctrl + ↑'
|
||||
},
|
||||
{
|
||||
icon: 'iconxiayi',
|
||||
name: '下移节点',
|
||||
value: 'Ctrl + ↓'
|
||||
},
|
||||
{
|
||||
icon: 'icongaikuozonglan',
|
||||
name: '插入概要',
|
||||
value: 'Ctrl + S'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhankai',
|
||||
name: '展开/收起节点',
|
||||
value: '/'
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: '删除节点',
|
||||
value: 'Delete | Backspace'
|
||||
},
|
||||
{
|
||||
icon: 'iconfuzhi',
|
||||
name: '复制节点',
|
||||
value: 'Ctrl + C'
|
||||
},
|
||||
{
|
||||
icon: 'iconjianqie',
|
||||
name: '剪切节点',
|
||||
value: 'Ctrl + X'
|
||||
},
|
||||
{
|
||||
icon: 'iconniantie',
|
||||
name: '粘贴节点',
|
||||
value: 'Ctrl + V'
|
||||
},
|
||||
{
|
||||
icon: 'iconbianji',
|
||||
name: '编辑节点',
|
||||
value: 'F2'
|
||||
},
|
||||
{
|
||||
icon: 'iconhuanhang',
|
||||
name: '文本换行',
|
||||
value: 'Shift + Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconhoutui-shi',
|
||||
name: '回退',
|
||||
value: 'Ctrl + Z'
|
||||
},
|
||||
{
|
||||
icon: 'iconqianjin1',
|
||||
name: '前进',
|
||||
value: 'Ctrl + Y'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: '全选',
|
||||
value: 'Ctrl + A'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: '多选',
|
||||
value: '右键 / Ctrl + 左键'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhengli',
|
||||
name: '一键整理布局',
|
||||
value: 'Ctrl + L'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: '画布操作',
|
||||
list: [
|
||||
{
|
||||
icon: 'iconfangda',
|
||||
name: '放大',
|
||||
value: 'Ctrl + +'
|
||||
},
|
||||
{
|
||||
icon: 'iconsuoxiao',
|
||||
name: '缩小',
|
||||
value: 'Ctrl + -'
|
||||
},
|
||||
{
|
||||
icon: 'icondingwei',
|
||||
name: '恢复默认',
|
||||
value: 'Ctrl + Enter'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
const borderDasharrayList = {
|
||||
zh: borderDasharrayListZh,
|
||||
en: borderDasharrayListEn
|
||||
}
|
||||
|
||||
// 形状列表
|
||||
export const shapeList = [
|
||||
{
|
||||
name: '矩形',
|
||||
value: 'rectangle'
|
||||
},
|
||||
{
|
||||
name: '菱形',
|
||||
value: 'diamond'
|
||||
},
|
||||
{
|
||||
name: '平行四边形',
|
||||
value: 'parallelogram'
|
||||
},
|
||||
{
|
||||
name: '圆角矩形',
|
||||
value: 'roundedRectangle'
|
||||
},
|
||||
{
|
||||
name: '八角矩形',
|
||||
value: 'octagonalRectangle'
|
||||
},
|
||||
{
|
||||
name: '外三角矩形',
|
||||
value: 'outerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: '内三角矩形',
|
||||
value: 'innerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: '椭圆',
|
||||
value: 'ellipse'
|
||||
},
|
||||
{
|
||||
name: '圆',
|
||||
value: 'circle'
|
||||
}
|
||||
]
|
||||
const lineStyleList = {
|
||||
zh: lineStyleListZh,
|
||||
en: lineStyleListEn
|
||||
}
|
||||
|
||||
const backgroundRepeatList = {
|
||||
zh: backgroundRepeatListZh,
|
||||
en: backgroundRepeatListEn
|
||||
}
|
||||
|
||||
const backgroundPositionList = {
|
||||
zh: backgroundPositionListZh,
|
||||
en: backgroundPositionListEn
|
||||
}
|
||||
|
||||
const shortcutKeyList = {
|
||||
zh: shortcutKeyListZh,
|
||||
en: shortcutKeyListEn
|
||||
}
|
||||
|
||||
const shapeList = {
|
||||
zh: shapeListZh,
|
||||
en: shapeListEn
|
||||
}
|
||||
|
||||
const sidebarTriggerList = {
|
||||
zh: sidebarTriggerListZh,
|
||||
en: sidebarTriggerListEn
|
||||
}
|
||||
|
||||
export {
|
||||
fontSizeList,
|
||||
lineHeightList,
|
||||
borderWidthList,
|
||||
borderRadiusList,
|
||||
lineWidthList,
|
||||
store,
|
||||
colorList,
|
||||
langList,
|
||||
fontFamilyList,
|
||||
borderDasharrayList,
|
||||
lineStyleList,
|
||||
backgroundRepeatList,
|
||||
backgroundPositionList,
|
||||
shortcutKeyList,
|
||||
shapeList,
|
||||
sidebarTriggerList
|
||||
}
|
||||
|
||||
427
web/src/config/zh.js
Normal file
427
web/src/config/zh.js
Normal file
@@ -0,0 +1,427 @@
|
||||
// 字体列表
|
||||
export const fontFamilyList = [
|
||||
{
|
||||
name: '宋体',
|
||||
value: '宋体, SimSun, Songti SC'
|
||||
},
|
||||
{
|
||||
name: '微软雅黑',
|
||||
value: '微软雅黑, Microsoft YaHei'
|
||||
},
|
||||
{
|
||||
name: '楷体',
|
||||
value: '楷体, 楷体_GB2312, SimKai, STKaiti'
|
||||
},
|
||||
{
|
||||
name: '黑体',
|
||||
value: '黑体, SimHei, Heiti SC'
|
||||
},
|
||||
{
|
||||
name: '隶书',
|
||||
value: '隶书, SimLi'
|
||||
},
|
||||
{
|
||||
name: 'Andale Mono',
|
||||
value: 'andale mono'
|
||||
},
|
||||
{
|
||||
name: 'Arial',
|
||||
value: 'arial, helvetica, sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'arialBlack',
|
||||
value: 'arial black, avant garde'
|
||||
},
|
||||
{
|
||||
name: 'Comic Sans Ms',
|
||||
value: 'comic sans ms'
|
||||
},
|
||||
{
|
||||
name: 'Impact',
|
||||
value: 'impact, chicago'
|
||||
},
|
||||
{
|
||||
name: 'Times New Roman',
|
||||
value: 'times new roman'
|
||||
},
|
||||
{
|
||||
name: 'Sans-Serif',
|
||||
value: 'sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'serif',
|
||||
value: 'serif'
|
||||
}
|
||||
]
|
||||
|
||||
// 字号
|
||||
export const fontSizeList = [10, 12, 16, 18, 24, 32, 48]
|
||||
|
||||
// 行高
|
||||
export const lineHeightList = [1, 1.5, 2, 2.5, 3]
|
||||
|
||||
// 颜色
|
||||
export const colorList = [
|
||||
'#4D4D4D',
|
||||
'#999999',
|
||||
'#FFFFFF',
|
||||
'#F44E3B',
|
||||
'#FE9200',
|
||||
'#FCDC00',
|
||||
'#DBDF00',
|
||||
'#A4DD00',
|
||||
'#68CCCA',
|
||||
'#73D8FF',
|
||||
'#AEA1FF',
|
||||
'#FDA1FF',
|
||||
'#333333',
|
||||
'#808080',
|
||||
'#cccccc',
|
||||
'#D33115',
|
||||
'#E27300',
|
||||
'#FCC400',
|
||||
'#B0BC00',
|
||||
'#68BC00',
|
||||
'#16A5A5',
|
||||
'#009CE0',
|
||||
'#7B64FF',
|
||||
'#FA28FF',
|
||||
'#000000',
|
||||
'#666666',
|
||||
'#B3B3B3',
|
||||
'#9F0500',
|
||||
'#C45100',
|
||||
'#FB9E00',
|
||||
'#808900',
|
||||
'#194D33',
|
||||
'#0C797D',
|
||||
'#0062B1',
|
||||
'#653294',
|
||||
'#AB149E'
|
||||
]
|
||||
|
||||
// 边框宽度
|
||||
export const borderWidthList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 边框样式
|
||||
export const borderDasharrayList = [
|
||||
{
|
||||
name: '实线',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
name: '虚线1',
|
||||
value: '5,5'
|
||||
},
|
||||
{
|
||||
name: '虚线2',
|
||||
value: '10,10'
|
||||
},
|
||||
{
|
||||
name: '虚线3',
|
||||
value: '20,10,5,5,5,10'
|
||||
},
|
||||
{
|
||||
name: '虚线4',
|
||||
value: '5, 5, 1, 5'
|
||||
},
|
||||
{
|
||||
name: '虚线5',
|
||||
value: '15, 10, 5, 10, 15'
|
||||
},
|
||||
{
|
||||
name: '虚线6',
|
||||
value: '1, 5'
|
||||
}
|
||||
]
|
||||
|
||||
// 圆角
|
||||
export const borderRadiusList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 线宽
|
||||
export const lineWidthList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// 连线风格
|
||||
export const lineStyleList = [
|
||||
{
|
||||
name: '直线',
|
||||
value: 'straight'
|
||||
},
|
||||
{
|
||||
name: '曲线',
|
||||
value: 'curve'
|
||||
},
|
||||
{
|
||||
name: '直连',
|
||||
value: 'direct'
|
||||
}
|
||||
]
|
||||
|
||||
// 图片重复方式
|
||||
export const backgroundRepeatList = [
|
||||
{
|
||||
name: '不重复',
|
||||
value: 'no-repeat'
|
||||
},
|
||||
{
|
||||
name: '重复',
|
||||
value: 'repeat'
|
||||
},
|
||||
{
|
||||
name: '水平方向重复',
|
||||
value: 'repeat-x'
|
||||
},
|
||||
{
|
||||
name: '垂直方向重复',
|
||||
value: 'repeat-y'
|
||||
}
|
||||
]
|
||||
|
||||
// 背景图片定位
|
||||
export const backgroundPositionList = [
|
||||
{
|
||||
name: '默认',
|
||||
value: '0% 0%'
|
||||
},
|
||||
{
|
||||
name: '左上',
|
||||
value: 'left top'
|
||||
},
|
||||
{
|
||||
name: '左中',
|
||||
value: 'left center'
|
||||
},
|
||||
{
|
||||
name: '左下',
|
||||
value: 'left bottom'
|
||||
},
|
||||
{
|
||||
name: '右上',
|
||||
value: 'right top'
|
||||
},
|
||||
{
|
||||
name: '右中',
|
||||
value: 'right center'
|
||||
},
|
||||
{
|
||||
name: '右下',
|
||||
value: 'right bottom'
|
||||
},
|
||||
{
|
||||
name: '中上',
|
||||
value: 'center top'
|
||||
},
|
||||
{
|
||||
name: '居中',
|
||||
value: 'center center'
|
||||
},
|
||||
{
|
||||
name: '中下',
|
||||
value: 'center bottom'
|
||||
}
|
||||
]
|
||||
|
||||
// 数据存储
|
||||
export const store = {
|
||||
sidebarZIndex: 1 //侧边栏zIndex
|
||||
}
|
||||
|
||||
// 快捷键列表
|
||||
export const shortcutKeyList = [
|
||||
{
|
||||
type: '节点操作',
|
||||
list: [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: '插入下级节点',
|
||||
value: 'Tab'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
name: '插入同级节点',
|
||||
value: 'Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconshangyi',
|
||||
name: '上移节点',
|
||||
value: 'Ctrl + ↑'
|
||||
},
|
||||
{
|
||||
icon: 'iconxiayi',
|
||||
name: '下移节点',
|
||||
value: 'Ctrl + ↓'
|
||||
},
|
||||
{
|
||||
icon: 'icongaikuozonglan',
|
||||
name: '插入概要',
|
||||
value: 'Ctrl + S'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhankai',
|
||||
name: '展开/收起节点',
|
||||
value: '/'
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: '删除节点',
|
||||
value: 'Delete | Backspace'
|
||||
},
|
||||
{
|
||||
icon: 'iconfuzhi',
|
||||
name: '复制节点',
|
||||
value: 'Ctrl + C'
|
||||
},
|
||||
{
|
||||
icon: 'iconjianqie',
|
||||
name: '剪切节点',
|
||||
value: 'Ctrl + X'
|
||||
},
|
||||
{
|
||||
icon: 'iconniantie',
|
||||
name: '粘贴节点',
|
||||
value: 'Ctrl + V'
|
||||
},
|
||||
{
|
||||
icon: 'iconbianji',
|
||||
name: '编辑节点',
|
||||
value: 'F2'
|
||||
},
|
||||
{
|
||||
icon: 'iconhuanhang',
|
||||
name: '文本换行',
|
||||
value: 'Shift + Enter'
|
||||
},
|
||||
{
|
||||
icon: 'iconhoutui-shi',
|
||||
name: '回退',
|
||||
value: 'Ctrl + Z'
|
||||
},
|
||||
{
|
||||
icon: 'iconqianjin1',
|
||||
name: '前进',
|
||||
value: 'Ctrl + Y'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: '全选',
|
||||
value: 'Ctrl + A'
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: '多选',
|
||||
value: '右键 / Ctrl + 左键'
|
||||
},
|
||||
{
|
||||
icon: 'iconzhengli',
|
||||
name: '一键整理布局',
|
||||
value: 'Ctrl + L'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: '画布操作',
|
||||
list: [
|
||||
{
|
||||
icon: 'iconfangda',
|
||||
name: '放大',
|
||||
value: 'Ctrl + +'
|
||||
},
|
||||
{
|
||||
icon: 'iconsuoxiao',
|
||||
name: '缩小',
|
||||
value: 'Ctrl + -'
|
||||
},
|
||||
{
|
||||
icon: 'icondingwei',
|
||||
name: '恢复默认',
|
||||
value: 'Ctrl + Enter'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 形状列表
|
||||
export const shapeList = [
|
||||
{
|
||||
name: '矩形',
|
||||
value: 'rectangle'
|
||||
},
|
||||
{
|
||||
name: '菱形',
|
||||
value: 'diamond'
|
||||
},
|
||||
{
|
||||
name: '平行四边形',
|
||||
value: 'parallelogram'
|
||||
},
|
||||
{
|
||||
name: '圆角矩形',
|
||||
value: 'roundedRectangle'
|
||||
},
|
||||
{
|
||||
name: '八角矩形',
|
||||
value: 'octagonalRectangle'
|
||||
},
|
||||
{
|
||||
name: '外三角矩形',
|
||||
value: 'outerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: '内三角矩形',
|
||||
value: 'innerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: '椭圆',
|
||||
value: 'ellipse'
|
||||
},
|
||||
{
|
||||
name: '圆',
|
||||
value: 'circle'
|
||||
}
|
||||
]
|
||||
|
||||
// 多语言列表
|
||||
export const langList = [
|
||||
{
|
||||
value: 'zh',
|
||||
name: '简体中文'
|
||||
},
|
||||
{
|
||||
value: 'en',
|
||||
name: 'English'
|
||||
}
|
||||
]
|
||||
|
||||
// 侧边栏列表
|
||||
export const sidebarTriggerList = [
|
||||
{
|
||||
name: '节点样式',
|
||||
value: 'nodeStyle',
|
||||
icon: 'iconzhuti'
|
||||
},
|
||||
{
|
||||
name: '基础样式',
|
||||
value: 'baseStyle',
|
||||
icon: 'iconyangshi'
|
||||
},
|
||||
{
|
||||
name: '主题',
|
||||
value: 'theme',
|
||||
icon: 'iconjingzi'
|
||||
},
|
||||
{
|
||||
name: '结构',
|
||||
value: 'structure',
|
||||
icon: 'iconjiegou'
|
||||
},
|
||||
{
|
||||
name: '大纲',
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: '快捷键',
|
||||
value: 'shortcutKey',
|
||||
icon: 'iconjianpan'
|
||||
}
|
||||
]
|
||||
13
web/src/i18n.js
Normal file
13
web/src/i18n.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import Vue from 'vue'
|
||||
import VueI18n from 'vue-i18n'
|
||||
import messages from './lang'
|
||||
import { getLang } from '@/api'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
const i18n = new VueI18n({
|
||||
locale: getLang(),
|
||||
messages
|
||||
})
|
||||
|
||||
export default i18n
|
||||
167
web/src/lang/en_us.js
Normal file
167
web/src/lang/en_us.js
Normal file
@@ -0,0 +1,167 @@
|
||||
export default {
|
||||
baseStyle: {
|
||||
title: 'BaseStyle',
|
||||
background: 'Background',
|
||||
color: 'Color',
|
||||
image: 'Image',
|
||||
imageRepeat: 'Image repeat',
|
||||
line: 'Line',
|
||||
width: 'Width',
|
||||
style: 'Style',
|
||||
lineOfOutline: 'Line of outline',
|
||||
nodePadding: 'Node padding',
|
||||
nodeMargin: 'Node margin',
|
||||
horizontal: 'Horizontal',
|
||||
vertical: 'Vertical',
|
||||
maximumWidth: 'Max width',
|
||||
maximumHeight: 'Max height',
|
||||
icon: 'Icon',
|
||||
size: 'Size',
|
||||
level2Node: 'Level2 node',
|
||||
belowLevel2Node: 'Below level2 node',
|
||||
nodeBorderType: 'Node border style',
|
||||
nodeUseLineStyle: 'Use only has bottom border style'
|
||||
},
|
||||
color: {
|
||||
moreColor: 'More color'
|
||||
},
|
||||
contextmenu: {
|
||||
insertSiblingNode: 'Insert sibling node',
|
||||
insertChildNode: 'Insert child node',
|
||||
insertSummary: 'Insert summary',
|
||||
moveUpNode: 'Move up node',
|
||||
moveDownNode: 'Move down node',
|
||||
deleteNode: 'Delete node',
|
||||
copyNode: 'Copy node',
|
||||
cutNode: 'Cut node',
|
||||
pasteNode: 'Paste node',
|
||||
backCenter: 'Back center',
|
||||
expandAll: 'Expand all',
|
||||
unExpandAll: 'Un expand all',
|
||||
expandTo: 'Expand to',
|
||||
arrangeLayout: 'Arrange layout',
|
||||
level1: 'Level1',
|
||||
level2: 'Level2',
|
||||
level3: 'Level3',
|
||||
level4: 'Level4',
|
||||
level5: 'Level5',
|
||||
level6: 'Level6',
|
||||
zenMode: 'Zen mode'
|
||||
},
|
||||
count: {
|
||||
words: 'Words',
|
||||
nodes: 'Nodes'
|
||||
},
|
||||
dialog: {
|
||||
cancel: 'Cancel',
|
||||
confirm: 'Confirm'
|
||||
},
|
||||
export: {
|
||||
title: 'Export',
|
||||
filename: 'Filename',
|
||||
include: 'Is include config like theme and structure',
|
||||
dedicatedFile: 'Dedicated file',
|
||||
jsonFile: 'json file',
|
||||
imageFile: 'Image file',
|
||||
svgFile: 'svg file',
|
||||
pdfFile: 'pdf file',
|
||||
tips: 'tips:.smm and .json file can be import'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreen: 'Fullscreen'
|
||||
},
|
||||
import: {
|
||||
title: 'Import',
|
||||
selectFile: 'Select file',
|
||||
supportFile: 'Support .smm、.json、.xmind、.xlsx file'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: 'Open mini map',
|
||||
readonly: 'Readonly',
|
||||
edit: 'Edit'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: 'Link',
|
||||
link: 'Href',
|
||||
name: 'Name'
|
||||
},
|
||||
nodeIcon: {
|
||||
title: 'Icon'
|
||||
},
|
||||
nodeImage: {
|
||||
title: 'Image',
|
||||
imgTitle: 'Title'
|
||||
},
|
||||
nodeNote: {
|
||||
title: 'Note'
|
||||
},
|
||||
nodeTag: {
|
||||
title: 'Tag',
|
||||
addTip: 'Press Enter to add'
|
||||
},
|
||||
outline: {
|
||||
title: 'Outline'
|
||||
},
|
||||
scale: {
|
||||
zoomIn: 'Zoom in',
|
||||
zoomOut: 'Zoom out'
|
||||
},
|
||||
shortcutKey: {
|
||||
title: 'Shortcut key'
|
||||
},
|
||||
strusture: {
|
||||
title: 'Strusture'
|
||||
},
|
||||
style: {
|
||||
title: 'Node style',
|
||||
normal: 'Normal',
|
||||
active: 'Active',
|
||||
text: 'Text',
|
||||
fontFamily: 'Font family',
|
||||
fontSize: 'Font size',
|
||||
lineHeight: 'Line height',
|
||||
color: 'color',
|
||||
addFontWeight: 'add font weight',
|
||||
italic: 'Italic',
|
||||
textDecoration: 'Text decoration',
|
||||
underline: 'Underline',
|
||||
lineThrough: 'Line through',
|
||||
overline: 'Overline',
|
||||
border: 'Border',
|
||||
style: 'Style',
|
||||
width: 'Width',
|
||||
borderRadius: 'Border radius',
|
||||
background: 'Background',
|
||||
shape: 'Shape',
|
||||
line: 'Line',
|
||||
nodePadding: 'Node padding',
|
||||
horizontal: 'Horizontal',
|
||||
vertical: 'Vertical'
|
||||
},
|
||||
theme: {
|
||||
title: 'Theme'
|
||||
},
|
||||
toolbar: {
|
||||
undo: 'Undo',
|
||||
redo: 'Redo',
|
||||
insertSiblingNode: 'Insert sibling node',
|
||||
insertChildNode: 'Insert child node',
|
||||
deleteNode: 'Delete node',
|
||||
image: 'Image',
|
||||
icon: 'Icon',
|
||||
link: 'Link',
|
||||
note: 'Note',
|
||||
tag: 'Tag',
|
||||
summary: 'Summary',
|
||||
displayOutline: 'Display outline',
|
||||
baseStyle: 'Base style',
|
||||
theme: 'Theme',
|
||||
strusture: 'Strusture',
|
||||
newFile: 'New file',
|
||||
openFile: 'Open file',
|
||||
saveAs: 'Save as',
|
||||
import: 'Import',
|
||||
export: 'Export',
|
||||
shortcutKey: 'Shortcut key'
|
||||
}
|
||||
}
|
||||
7
web/src/lang/index.js
Normal file
7
web/src/lang/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import en from './en_us'
|
||||
import zh from './zh_cn'
|
||||
|
||||
export default {
|
||||
zh,
|
||||
en
|
||||
}
|
||||
167
web/src/lang/zh_cn.js
Normal file
167
web/src/lang/zh_cn.js
Normal file
@@ -0,0 +1,167 @@
|
||||
export default {
|
||||
baseStyle: {
|
||||
title: '基础样式',
|
||||
background: '背景',
|
||||
color: '颜色',
|
||||
image: '图片',
|
||||
imageRepeat: '图片重复',
|
||||
line: '连线',
|
||||
width: '粗细',
|
||||
style: '风格',
|
||||
lineOfOutline: '概要的连线',
|
||||
nodePadding: '节点内边距',
|
||||
nodeMargin: '节点外边距',
|
||||
horizontal: '水平',
|
||||
vertical: '垂直',
|
||||
maximumWidth: '显示的最大宽度',
|
||||
maximumHeight: '显示的最大高度',
|
||||
icon: '图标',
|
||||
size: '大小',
|
||||
level2Node: '二级节点',
|
||||
belowLevel2Node: '三级及以下节点',
|
||||
nodeBorderType: '节点边框风格',
|
||||
nodeUseLineStyle: '是否使用只有底边框的风格'
|
||||
},
|
||||
color: {
|
||||
moreColor: '更多颜色'
|
||||
},
|
||||
contextmenu: {
|
||||
insertSiblingNode: '插入同级节点',
|
||||
insertChildNode: '插入子级节点',
|
||||
insertSummary: '插入概要',
|
||||
moveUpNode: '上移节点',
|
||||
moveDownNode: '下移节点',
|
||||
deleteNode: '删除节点',
|
||||
copyNode: '复制节点',
|
||||
cutNode: '剪切节点',
|
||||
pasteNode: '粘贴节点',
|
||||
backCenter: '回到中心',
|
||||
expandAll: '展开所有',
|
||||
unExpandAll: '收起所有',
|
||||
expandTo: '展开到',
|
||||
arrangeLayout: '一键整理布局',
|
||||
level1: '一级主题',
|
||||
level2: '二级主题',
|
||||
level3: '三级主题',
|
||||
level4: '四级主题',
|
||||
level5: '五级主题',
|
||||
level6: '六级主题',
|
||||
zenMode: '禅模式'
|
||||
},
|
||||
count: {
|
||||
words: '字数',
|
||||
nodes: '节点'
|
||||
},
|
||||
dialog: {
|
||||
cancel: '取 消',
|
||||
confirm: '确 定'
|
||||
},
|
||||
export: {
|
||||
title: '导出',
|
||||
filename: '导出文件名称',
|
||||
include: '是否包含主题、结构等配置数据',
|
||||
dedicatedFile: '专有文件',
|
||||
jsonFile: 'json文件',
|
||||
imageFile: '图片文件',
|
||||
svgFile: 'svg文件',
|
||||
pdfFile: 'pdf文件',
|
||||
tips: 'tips:.smm和.json文件可用于导入'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreen: '全屏'
|
||||
},
|
||||
import: {
|
||||
title: '导入',
|
||||
selectFile: '选取文件',
|
||||
supportFile: '支持.smm、.json、.xmind、.xlsx文件'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: '开启小地图',
|
||||
readonly: '只读模式',
|
||||
edit: '编辑模式'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: '超链接',
|
||||
link: '链接',
|
||||
name: '名称'
|
||||
},
|
||||
nodeIcon: {
|
||||
title: '图标'
|
||||
},
|
||||
nodeImage: {
|
||||
title: '图片',
|
||||
imgTitle: '图片标题'
|
||||
},
|
||||
nodeNote: {
|
||||
title: '备注'
|
||||
},
|
||||
nodeTag: {
|
||||
title: '标签',
|
||||
addTip: '请按回车键添加'
|
||||
},
|
||||
outline: {
|
||||
title: '大纲'
|
||||
},
|
||||
scale: {
|
||||
zoomIn: '放大',
|
||||
zoomOut: '缩小'
|
||||
},
|
||||
shortcutKey: {
|
||||
title: '快捷键'
|
||||
},
|
||||
strusture: {
|
||||
title: '结构'
|
||||
},
|
||||
style: {
|
||||
title: '节点样式',
|
||||
normal: '常态',
|
||||
active: '选中状态',
|
||||
text: '文字',
|
||||
fontFamily: '字体',
|
||||
fontSize: '字号',
|
||||
lineHeight: '行高',
|
||||
color: '颜色',
|
||||
addFontWeight: '加粗',
|
||||
italic: '斜体',
|
||||
textDecoration: '划线',
|
||||
underline: '下划线',
|
||||
lineThrough: '中划线',
|
||||
overline: '上划线',
|
||||
border: '边框',
|
||||
style: '样式',
|
||||
width: '宽度',
|
||||
borderRadius: '圆角',
|
||||
background: '背景',
|
||||
shape: '形状',
|
||||
line: '线条',
|
||||
nodePadding: '节点内边距',
|
||||
horizontal: '水平',
|
||||
vertical: '垂直'
|
||||
},
|
||||
theme: {
|
||||
title: '主题'
|
||||
},
|
||||
toolbar: {
|
||||
undo: '回退',
|
||||
redo: '前进',
|
||||
insertSiblingNode: '插入同级节点',
|
||||
insertChildNode: '插入子节点',
|
||||
deleteNode: '删除节点',
|
||||
image: '图片',
|
||||
icon: '图标',
|
||||
link: '超链接',
|
||||
note: '备注',
|
||||
tag: '标签',
|
||||
summary: '概要',
|
||||
displayOutline: '显示大纲',
|
||||
baseStyle: '基础样式',
|
||||
theme: '主题',
|
||||
strusture: '结构',
|
||||
newFile: '新建',
|
||||
openFile: '打开',
|
||||
saveAs: '另存为',
|
||||
import: '导入',
|
||||
export: '导出',
|
||||
shortcutKey: '快捷键'
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'element-ui/lib/theme-chalk/index.css'
|
||||
import '@/assets/icon-font/iconfont.css'
|
||||
import 'viewerjs/dist/viewer.css'
|
||||
import VueViewer from 'v-viewer'
|
||||
import i18n from './i18n'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.prototype.$bus = new Vue()
|
||||
@@ -16,5 +17,6 @@ Vue.use(VueViewer)
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
router,
|
||||
store
|
||||
store,
|
||||
i18n
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<template v-if="show">
|
||||
<Toolbar></Toolbar>
|
||||
<Toolbar v-if="!isZenMode"></Toolbar>
|
||||
<Edit></Edit>
|
||||
</template>
|
||||
</div>
|
||||
@@ -10,7 +10,8 @@
|
||||
<script>
|
||||
import Toolbar from './components/Toolbar'
|
||||
import Edit from './components/Edit'
|
||||
import { mapActions } from 'vuex'
|
||||
import { mapState, mapActions, mapMutations } from 'vuex'
|
||||
import { getLocalConfig } from '@/api'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
@@ -23,7 +24,13 @@ export default {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isZenMode: state => state.localConfig.isZenMode
|
||||
})
|
||||
},
|
||||
async created() {
|
||||
this.initLocalConfig()
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在加载,请稍后...'
|
||||
@@ -33,7 +40,23 @@ export default {
|
||||
loading.close()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getUserMindMapData'])
|
||||
...mapActions(['getUserMindMapData']),
|
||||
...mapMutations(['setLocalConfig']),
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:07:03
|
||||
* @Desc: 初始化本地配置
|
||||
*/
|
||||
initLocalConfig() {
|
||||
let config = getLocalConfig()
|
||||
if (config) {
|
||||
this.setLocalConfig({
|
||||
...this.$store.state.localConfig,
|
||||
...config
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="基础样式">
|
||||
<Sidebar ref="sidebar" :title="$t('baseStyle.title')">
|
||||
<div class="sidebarContent" v-if="data">
|
||||
<!-- 背景 -->
|
||||
<div class="title noTop">背景</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.background') }}</div>
|
||||
<div class="row">
|
||||
<el-tabs class="tab" v-model="activeTab">
|
||||
<el-tab-pane label="颜色" name="color">
|
||||
<el-tab-pane :label="$t('baseStyle.color')" name="color">
|
||||
<Color
|
||||
:color="style.backgroundColor"
|
||||
@change="
|
||||
@@ -15,7 +15,7 @@
|
||||
"
|
||||
></Color>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="图片" name="image">
|
||||
<el-tab-pane :label="$t('baseStyle.image')" name="image">
|
||||
<ImgUpload
|
||||
class="imgUpload"
|
||||
v-model="style.backgroundImage"
|
||||
@@ -26,7 +26,7 @@
|
||||
"
|
||||
></ImgUpload>
|
||||
<div class="rowItem">
|
||||
<span class="name">图片重复</span>
|
||||
<span class="name">{{ $t('baseStyle.imageRepeat') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 120px"
|
||||
@@ -51,10 +51,10 @@
|
||||
</el-tabs>
|
||||
</div>
|
||||
<!-- 连线 -->
|
||||
<div class="title noTop">连线</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.line') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span class="name">{{ $t('baseStyle.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover
|
||||
@@ -72,7 +72,7 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">粗细</span>
|
||||
<span class="name">{{ $t('baseStyle.width') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">风格</span>
|
||||
<span class="name">{{ $t('baseStyle.style') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -119,10 +119,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 概要连线 -->
|
||||
<div class="title noTop">概要的连线</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.lineOfOutline') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span class="name">{{ $t('baseStyle.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover2
|
||||
@@ -140,7 +140,7 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">粗细</span>
|
||||
<span class="name">{{ $t('baseStyle.width') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -162,11 +162,22 @@
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内边距 -->
|
||||
<div class="title noTop">节点内边距</div>
|
||||
<!-- 节点边框风格 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.nodeBorderType') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">水平</span>
|
||||
<el-checkbox v-model="style.nodeUseLineStyle" @change="
|
||||
value => {
|
||||
update('nodeUseLineStyle', value)
|
||||
}
|
||||
">{{ $t('baseStyle.nodeUseLineStyle') }}</el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内边距 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.nodePadding') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.horizontal') }}</span>
|
||||
<el-slider
|
||||
style="width: 200px"
|
||||
v-model="style.paddingX"
|
||||
@@ -180,7 +191,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">垂直</span>
|
||||
<span class="name">{{ $t('baseStyle.vertical') }}</span>
|
||||
<el-slider
|
||||
style="width: 200px"
|
||||
v-model="style.paddingY"
|
||||
@@ -193,10 +204,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图片 -->
|
||||
<div class="title noTop">图片</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.image') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">显示的最大宽度</span>
|
||||
<span class="name">{{ $t('baseStyle.maximumWidth') }}</span>
|
||||
<el-slider
|
||||
style="width: 140px"
|
||||
v-model="style.imgMaxWidth"
|
||||
@@ -212,7 +223,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">显示的最大高度</span>
|
||||
<span class="name">{{ $t('baseStyle.maximumHeight') }}</span>
|
||||
<el-slider
|
||||
style="width: 140px"
|
||||
v-model="style.imgMaxHeight"
|
||||
@@ -227,10 +238,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图标 -->
|
||||
<div class="title noTop">图标</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.icon') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">大小</span>
|
||||
<span class="name">{{ $t('baseStyle.size') }}</span>
|
||||
<el-slider
|
||||
style="width: 200px"
|
||||
v-model="style.iconSize"
|
||||
@@ -245,18 +256,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 二级节点外边距 -->
|
||||
<div class="title noTop">节点外边距</div>
|
||||
<div class="title noTop">{{ $t('baseStyle.nodeMargin') }}</div>
|
||||
<div class="row column">
|
||||
<el-tabs
|
||||
class="tab"
|
||||
v-model="marginActiveTab"
|
||||
@tab-click="initMarginStyle"
|
||||
>
|
||||
<el-tab-pane label="二级节点" name="second"></el-tab-pane>
|
||||
<el-tab-pane label="三级及以下节点" name="node"></el-tab-pane>
|
||||
<el-tab-pane
|
||||
:label="$t('baseStyle.level2Node')"
|
||||
name="second"
|
||||
></el-tab-pane>
|
||||
<el-tab-pane
|
||||
:label="$t('baseStyle.belowLevel2Node')"
|
||||
name="node"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="rowItem">
|
||||
<span class="name">水平</span>
|
||||
<span class="name">{{ $t('baseStyle.horizontal') }}</span>
|
||||
<el-slider
|
||||
:max="200"
|
||||
style="width: 200px"
|
||||
@@ -269,7 +286,7 @@
|
||||
></el-slider>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">垂直</span>
|
||||
<span class="name">{{ $t('baseStyle.vertical') }}</span>
|
||||
<el-slider
|
||||
:max="200"
|
||||
style="width: 200px"
|
||||
@@ -292,6 +309,7 @@ import Color from './Color'
|
||||
import { lineWidthList, lineStyleList, backgroundRepeatList } from '@/config'
|
||||
import ImgUpload from '@/components/ImgUpload'
|
||||
import { storeConfig } from '@/api'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -317,8 +335,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
lineWidthList,
|
||||
lineStyleList,
|
||||
backgroundRepeatList,
|
||||
activeTab: 'color',
|
||||
marginActiveTab: 'second',
|
||||
style: {
|
||||
@@ -336,18 +352,30 @@ export default {
|
||||
backgroundImage: '',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
marginX: 0,
|
||||
marginY: 0
|
||||
marginY: 0,
|
||||
nodeUseLineStyle: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('showBaseStyle', () => {
|
||||
this.$refs.sidebar.show = false
|
||||
this.$nextTick(() => {
|
||||
computed: {
|
||||
...mapState(['activeSidebar']),
|
||||
|
||||
lineStyleList() {
|
||||
return lineStyleList[this.$i18n.locale] || lineStyleList.zh
|
||||
},
|
||||
backgroundRepeatList() {
|
||||
return backgroundRepeatList[this.$i18n.locale] || backgroundRepeatList.zh
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'baseStyle') {
|
||||
this.$refs.sidebar.show = true
|
||||
this.initStyle()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
@@ -369,7 +397,8 @@ export default {
|
||||
'imgMaxHeight',
|
||||
'iconSize',
|
||||
'backgroundImage',
|
||||
'backgroundRepeat'
|
||||
'backgroundRepeat',
|
||||
'nodeUseLineStyle'
|
||||
].forEach(key => {
|
||||
this.style[key] = this.mindMap.getThemeConfig(key)
|
||||
if (key === 'backgroundImage' && this.style[key] === 'none') {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
></span>
|
||||
</div>
|
||||
<div class="moreColor">
|
||||
<span>更多颜色</span>
|
||||
<span>{{ $t('color.moreColor') }}</span>
|
||||
<el-color-picker
|
||||
size="mini"
|
||||
v-model="selectColor"
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
@click="exec('INSERT_NODE', insertNodeBtnDisabled)"
|
||||
:class="{ disabled: insertNodeBtnDisabled }"
|
||||
>
|
||||
插入同级节点
|
||||
{{ $t('contextmenu.insertSiblingNode') }}
|
||||
<span class="desc">Enter</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('INSERT_CHILD_NODE')">
|
||||
插入子级节点
|
||||
{{ $t('contextmenu.insertChildNode') }}
|
||||
<span class="desc">Tab</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -22,7 +22,7 @@
|
||||
@click="exec('ADD_GENERALIZATION')"
|
||||
:class="{ disabled: insertNodeBtnDisabled }"
|
||||
>
|
||||
插入概要
|
||||
{{ $t('contextmenu.insertSummary') }}
|
||||
<span class="desc">Ctrl + S</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -30,7 +30,7 @@
|
||||
@click="exec('UP_NODE')"
|
||||
:class="{ disabled: upNodeBtnDisabled }"
|
||||
>
|
||||
上移节点
|
||||
{{ $t('contextmenu.moveUpNode') }}
|
||||
<span class="desc">Ctrl + ↑</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -38,19 +38,19 @@
|
||||
@click="exec('DOWN_NODE')"
|
||||
:class="{ disabled: downNodeBtnDisabled }"
|
||||
>
|
||||
下移节点
|
||||
{{ $t('contextmenu.moveDownNode') }}
|
||||
<span class="desc">Ctrl + ↓</span>
|
||||
</div>
|
||||
<div class="item danger" @click="exec('REMOVE_NODE')">
|
||||
删除节点
|
||||
{{ $t('contextmenu.deleteNode') }}
|
||||
<span class="desc">Delete</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('COPY_NODE')">
|
||||
复制节点
|
||||
{{ $t('contextmenu.copyNode') }}
|
||||
<span class="desc">Ctrl + C</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('CUT_NODE')">
|
||||
剪切节点
|
||||
{{ $t('contextmenu.cutNode') }}
|
||||
<span class="desc">Ctrl + X</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -58,16 +58,22 @@
|
||||
:class="{ disabled: copyData === null }"
|
||||
@click="exec('PASTE_NODE')"
|
||||
>
|
||||
粘贴节点
|
||||
{{ $t('contextmenu.pasteNode') }}
|
||||
<span class="desc">Ctrl + V</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="type === 'svg'">
|
||||
<div class="item" @click="exec('RETURN_CENTER')">回到中心</div>
|
||||
<div class="item" @click="exec('EXPAND_ALL')">展开所有</div>
|
||||
<div class="item" @click="exec('UNEXPAND_ALL')">收起所有</div>
|
||||
<div class="item" @click="exec('RETURN_CENTER')">
|
||||
{{ $t('contextmenu.backCenter') }}
|
||||
</div>
|
||||
<div class="item" @click="exec('EXPAND_ALL')">
|
||||
{{ $t('contextmenu.expandAll') }}
|
||||
</div>
|
||||
<div class="item" @click="exec('UNEXPAND_ALL')">
|
||||
{{ $t('contextmenu.unExpandAll') }}
|
||||
</div>
|
||||
<div class="item">
|
||||
展开到
|
||||
{{ $t('contextmenu.expandTo') }}
|
||||
<div class="subItems listBox">
|
||||
<div
|
||||
class="item"
|
||||
@@ -80,14 +86,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" @click="exec('RESET_LAYOUT')">
|
||||
一键整理布局
|
||||
{{ $t('contextmenu.arrangeLayout') }}
|
||||
<span class="desc">Ctrl + L</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('TOGGLE_ZEN_MODE')">
|
||||
{{ $t('contextmenu.zenMode') }}
|
||||
{{ isZenMode ? '√' : '' }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-24 22:53:10
|
||||
@@ -110,18 +122,23 @@ export default {
|
||||
type: '',
|
||||
isMousedown: false,
|
||||
mosuedownX: 0,
|
||||
mosuedownY: 0,
|
||||
expandList: [
|
||||
'一级主题',
|
||||
'二级主题',
|
||||
'三级主题',
|
||||
'四级主题',
|
||||
'五级主题',
|
||||
'六级主题'
|
||||
]
|
||||
mosuedownY: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isZenMode: state => state.localConfig.isZenMode
|
||||
}),
|
||||
expandList() {
|
||||
return [
|
||||
this.$t('contextmenu.level1'),
|
||||
this.$t('contextmenu.level2'),
|
||||
this.$t('contextmenu.level3'),
|
||||
this.$t('contextmenu.level4'),
|
||||
this.$t('contextmenu.level5'),
|
||||
this.$t('contextmenu.level6')
|
||||
]
|
||||
},
|
||||
insertNodeBtnDisabled() {
|
||||
return !this.node || this.node.isRoot
|
||||
},
|
||||
@@ -173,6 +190,8 @@ export default {
|
||||
this.mindMap.keyCommand.removeShortcut('Control+x', this.cut)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setLocalConfig']),
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-07-14 21:38:50
|
||||
@@ -268,6 +287,11 @@ export default {
|
||||
case 'RETURN_CENTER':
|
||||
this.mindMap.view.reset()
|
||||
break
|
||||
case 'TOGGLE_ZEN_MODE':
|
||||
this.setLocalConfig({
|
||||
isZenMode: !this.isZenMode
|
||||
})
|
||||
break
|
||||
default:
|
||||
this.$bus.$emit('execCommand', key, ...args)
|
||||
break
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="countContainer">
|
||||
<div class="item">
|
||||
<span class="name">字数</span>
|
||||
<span class="name">{{ $t('count.words') }}</span>
|
||||
<span class="value">{{ words }}</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="name">节点</span>
|
||||
<span class="name">{{ $t('count.nodes') }}</span>
|
||||
<span class="value">{{ num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,13 +27,23 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('data_change', data => {
|
||||
this.$bus.$on('data_change', this.onDataChange)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('data_change', this.onDataChange)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:20:20
|
||||
* @Desc: 监听数据变化
|
||||
*/
|
||||
onDataChange(data) {
|
||||
this.words = 0
|
||||
this.num = 0
|
||||
this.walk(data)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-30 22:13:07
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<template>
|
||||
<div class="editContainer">
|
||||
<div class="mindMapContainer" ref="mindMapContainer"></div>
|
||||
<Count></Count>
|
||||
<Count v-if="!isZenMode"></Count>
|
||||
<Navigator :mindMap="mindMap"></Navigator>
|
||||
<NavigatorToolbar :mindMap="mindMap"></NavigatorToolbar>
|
||||
<Outline></Outline>
|
||||
<Style></Style>
|
||||
<NavigatorToolbar :mindMap="mindMap" v-if="!isZenMode"></NavigatorToolbar>
|
||||
<Outline :mindMap="mindMap"></Outline>
|
||||
<Style v-if="!isZenMode"></Style>
|
||||
<BaseStyle :data="mindMapData" :mindMap="mindMap"></BaseStyle>
|
||||
<Theme :mindMap="mindMap"></Theme>
|
||||
<Structure :mindMap="mindMap"></Structure>
|
||||
<ShortcutKey></ShortcutKey>
|
||||
<Contextmenu v-if="mindMap" :mindMap="mindMap"></Contextmenu>
|
||||
<NodeNoteContentShow></NodeNoteContentShow>
|
||||
<NodeNoteContentShow
|
||||
v-if="mindMap"
|
||||
:mindMap="mindMap"
|
||||
></NodeNoteContentShow>
|
||||
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
||||
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -31,6 +35,8 @@ import NodeNoteContentShow from './NodeNoteContentShow.vue'
|
||||
import { getData, storeData, storeConfig } from '@/api'
|
||||
import Navigator from './Navigator.vue'
|
||||
import NodeImgPreview from './NodeImgPreview.vue'
|
||||
import SidebarTrigger from './SidebarTrigger.vue'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -51,7 +57,8 @@ export default {
|
||||
Contextmenu,
|
||||
NodeNoteContentShow,
|
||||
Navigator,
|
||||
NodeImgPreview
|
||||
NodeImgPreview,
|
||||
SidebarTrigger
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -61,6 +68,11 @@ export default {
|
||||
openTest: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isZenMode: state => state.localConfig.isZenMode
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
this.init()
|
||||
@@ -225,7 +237,7 @@ export default {
|
||||
this.$bus.$emit('showNoteContent', content, left, top)
|
||||
},
|
||||
hide: () => {
|
||||
this.$bus.$emit('hideNoteContent')
|
||||
// this.$bus.$emit('hideNoteContent')
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -316,6 +328,11 @@ export default {
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
// left: 100px;
|
||||
// top: 100px;
|
||||
// right: 100px;
|
||||
// bottom: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="导出"
|
||||
:title="$t('export.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="700px"
|
||||
>
|
||||
<div>
|
||||
<div class="nameInputBox">
|
||||
<span class="name">导出文件名称</span>
|
||||
<span class="name">{{ $t('export.filename') }}</span>
|
||||
<el-input
|
||||
style="width: 300px"
|
||||
v-model="fileName"
|
||||
@@ -17,21 +17,33 @@
|
||||
v-show="['smm', 'json'].includes(exportType)"
|
||||
v-model="widthConfig"
|
||||
style="margin-left: 12px"
|
||||
>是否包含主题、结构等配置数据</el-checkbox
|
||||
>{{ $t('export.include') }}</el-checkbox
|
||||
>
|
||||
</div>
|
||||
<el-radio-group v-model="exportType" size="mini">
|
||||
<el-radio-button label="smm">专有文件(.smm)</el-radio-button>
|
||||
<el-radio-button label="json">json文件(.json)</el-radio-button>
|
||||
<el-radio-button label="png">图片文件(.png)</el-radio-button>
|
||||
<el-radio-button label="svg">svg文件(.svg)</el-radio-button>
|
||||
<el-radio-button label="pdf">pdf文件(.pdf)</el-radio-button>
|
||||
<el-radio-button label="smm"
|
||||
>{{ $t('export.dedicatedFile') }}(.smm)</el-radio-button
|
||||
>
|
||||
<el-radio-button label="json"
|
||||
>{{ $t('export.jsonFile') }}(.json)</el-radio-button
|
||||
>
|
||||
<el-radio-button label="png"
|
||||
>{{ $t('export.imageFile') }}(.png)</el-radio-button
|
||||
>
|
||||
<el-radio-button label="svg"
|
||||
>{{ $t('export.svgFile') }}(.svg)</el-radio-button
|
||||
>
|
||||
<el-radio-button label="pdf"
|
||||
>{{ $t('export.pdfFile') }}(.pdf)</el-radio-button
|
||||
>
|
||||
</el-radio-group>
|
||||
<div class="tip">tips:.smm和.json文件可用于导入</div>
|
||||
<div class="tip">{{ $t('export.tips') }}</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div class="fullscreenContainer">
|
||||
<el-tooltip class="item" effect="dark" content="全屏" placement="top">
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="$t('fullscreen.fullscreen')"
|
||||
placement="top"
|
||||
>
|
||||
<div class="btn iconfont iconquanping" @click="toFullscreen"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="导入"
|
||||
:title="$t('import.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="300px"
|
||||
>
|
||||
@@ -15,14 +15,18 @@
|
||||
:limit="1"
|
||||
:on-exceed="onExceed"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
|
||||
<el-button slot="trigger" size="small" type="primary">{{
|
||||
$t('import.selectFile')
|
||||
}}</el-button>
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
支持.smm、.json、.xmind、.xlsx文件
|
||||
{{ $t('import.supportFile') }}
|
||||
</div>
|
||||
</el-upload>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
<template>
|
||||
<div class="navigatorContainer">
|
||||
<div class="item">
|
||||
<el-checkbox v-model="openMiniMap" @change="toggleMiniMap"
|
||||
>开启小地图</el-checkbox
|
||||
<el-select
|
||||
v-model="lang"
|
||||
size="small"
|
||||
style="width: 100px"
|
||||
@change="onLangChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in langList"
|
||||
:key="item.value"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-checkbox v-model="openMiniMap" @change="toggleMiniMap">{{
|
||||
$t('navigatorToolbar.openMiniMap')
|
||||
}}</el-checkbox>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-switch
|
||||
v-model="isReadonly"
|
||||
active-text="只读模式"
|
||||
inactive-text="编辑模式"
|
||||
:active-text="$t('navigatorToolbar.readonly')"
|
||||
:inactive-text="$t('navigatorToolbar.edit')"
|
||||
@change="readonlyChange"
|
||||
>
|
||||
</el-switch>
|
||||
@@ -26,6 +41,9 @@
|
||||
<script>
|
||||
import Scale from './Scale'
|
||||
import Fullscreen from './Fullscreen'
|
||||
import { langList } from '@/config'
|
||||
import i18n from '@/i18n'
|
||||
import { storeLang, getLang } from '@/api'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -45,6 +63,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
langList,
|
||||
lang: getLang(),
|
||||
isReadonly: false,
|
||||
openMiniMap: false
|
||||
}
|
||||
@@ -59,6 +79,11 @@ export default {
|
||||
|
||||
toggleMiniMap(show) {
|
||||
this.$bus.$emit('toggle_mini_map', show)
|
||||
},
|
||||
|
||||
onLangChange(lang) {
|
||||
i18n.locale = lang
|
||||
storeLang(lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="超链接"
|
||||
:title="$t('nodeHyperlink.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500"
|
||||
>
|
||||
<div class="item">
|
||||
<span class="name">链接</span>
|
||||
<span class="name">{{ $t('nodeHyperlink.link') }}</span>
|
||||
<el-input
|
||||
v-model="link"
|
||||
size="mini"
|
||||
placeholder="http://xxxx.com/"
|
||||
@keyup.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="name">名称</span>
|
||||
<el-input v-model="linkTitle" size="mini"></el-input>
|
||||
<span class="name">{{ $t('nodeHyperlink.name') }}</span>
|
||||
<el-input v-model="linkTitle" size="mini" @keyup.native.stop></el-input>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="图标"
|
||||
:title="$t('nodeIcon.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500"
|
||||
>
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="图片"
|
||||
:title="$t('nodeImage.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500"
|
||||
>
|
||||
<ImgUpload ref="ImgUpload" v-model="img"></ImgUpload>
|
||||
<div class="imgTitleBox">
|
||||
<span class="title">图片标题</span>
|
||||
<span class="title">{{ $t('nodeImage.imgTitle') }}</span>
|
||||
<el-input v-model="imgTitle" size="mini"></el-input>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="备注"
|
||||
:title="$t('nodeNote.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500"
|
||||
>
|
||||
@@ -12,11 +12,13 @@
|
||||
v-model="note"
|
||||
>
|
||||
</el-input> -->
|
||||
<div class="noteEditor" ref="noteEditor"></div>
|
||||
<div class="noteEditor" ref="noteEditor" @keyup.stop></div>
|
||||
<!-- <div class="tip">换行请使用:Enter+Shift</div> -->
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
top: this.top + 'px',
|
||||
visibility: show ? 'visible' : 'hidden'
|
||||
}"
|
||||
@click.stop
|
||||
></div>
|
||||
</template>
|
||||
|
||||
@@ -30,20 +31,42 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('showNoteContent', (content, left, top) => {
|
||||
this.editor.setMarkdown(content)
|
||||
this.left = left
|
||||
this.top = top
|
||||
this.show = true
|
||||
})
|
||||
this.$bus.$on('hideNoteContent', () => {
|
||||
this.show = false
|
||||
})
|
||||
this.$bus.$on('showNoteContent', this.onShowNoteContent)
|
||||
this.$bus.$on('hideNoteContent', this.hideNoteContent)
|
||||
document.body.addEventListener('click', this.hideNoteContent)
|
||||
this.$bus.$on('node_active', this.hideNoteContent)
|
||||
},
|
||||
mounted() {
|
||||
this.initEditor()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('showNoteContent', this.onShowNoteContent)
|
||||
this.$bus.$off('hideNoteContent', this.hideNoteContent)
|
||||
document.body.removeEventListener('click', this.hideNoteContent)
|
||||
this.$bus.$off('node_active', this.hideNoteContent)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:56:08
|
||||
* @Desc: 显示备注浮层
|
||||
*/
|
||||
onShowNoteContent(content, left, top) {
|
||||
this.editor.setMarkdown(content)
|
||||
this.left = left
|
||||
this.top = top
|
||||
this.show = true
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:56:20
|
||||
* @Desc: 隐藏备注浮层
|
||||
*/
|
||||
hideNoteContent() {
|
||||
this.show = false
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-05-09 11:37:05
|
||||
@@ -66,5 +89,24 @@ export default {
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 7px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeDialog"
|
||||
title="标签"
|
||||
:title="$t('nodeTag.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500"
|
||||
>
|
||||
<el-input
|
||||
v-model="tag"
|
||||
@keyup.native.enter="add"
|
||||
@keyup.native.stop
|
||||
:disabled="tagArr.length >= max"
|
||||
placeholder="请按回车键添加"
|
||||
:placeholder="$t('nodeTag.addTip')"
|
||||
>
|
||||
</el-input>
|
||||
<div class="tagList">
|
||||
@@ -29,8 +30,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="大纲">
|
||||
<el-tree :data="data" :props="defaultProps" default-expand-all></el-tree>
|
||||
<Sidebar ref="sidebar" :title="$t('outline.title')">
|
||||
<el-tree
|
||||
class="outlineTree"
|
||||
:data="data"
|
||||
:props="defaultProps"
|
||||
:expand-on-click-node="false"
|
||||
default-expand-all
|
||||
>
|
||||
<span class="customNode" slot-scope="{ node, data }">
|
||||
<span
|
||||
class="nodeEdit"
|
||||
:key="getKey()"
|
||||
contenteditable="true"
|
||||
@keydown.stop
|
||||
@keyup.stop
|
||||
@blur="onBlur($event, node)"
|
||||
v-html="node.label"
|
||||
></span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</Sidebar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sidebar from './Sidebar'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -17,28 +36,97 @@ export default {
|
||||
components: {
|
||||
Sidebar
|
||||
},
|
||||
props: {
|
||||
mindMap: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: [],
|
||||
defaultProps: {
|
||||
label(data) {
|
||||
return data.data.text
|
||||
return data.data.text.replaceAll(/\n/g, '</br>')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['activeSidebar'])
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'outline') {
|
||||
this.$refs.sidebar.show = true
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('data_change', data => {
|
||||
this.data = [data]
|
||||
})
|
||||
this.$bus.$on('showOutline', () => {
|
||||
this.$refs.sidebar.show = false
|
||||
this.$nextTick(() => {
|
||||
this.$refs.sidebar.show = true
|
||||
})
|
||||
this.data = [this.mindMap.renderer.renderTree]
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onBlur(e, node) {
|
||||
node.data._node.setText(e.target.innerText)
|
||||
},
|
||||
|
||||
getKey() {
|
||||
return Math.random()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<style lang="less" scoped>
|
||||
.customNode {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 7px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nodeEdit {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.outlineTree {
|
||||
/deep/ .el-tree-node__content {
|
||||
height: auto;
|
||||
margin: 5px 0;
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
background-color: #c0c4cc;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
<template>
|
||||
<div class="scaleContainer">
|
||||
<el-tooltip class="item" effect="dark" content="缩小" placement="top">
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="$t('scale.zoomOut')"
|
||||
placement="top"
|
||||
>
|
||||
<div class="btn el-icon-minus" @click="narrow"></div>
|
||||
</el-tooltip>
|
||||
<div class="scaleInfo">{{ scaleNum }}%</div>
|
||||
<el-tooltip class="item" effect="dark" content="放大" placement="top">
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="$t('scale.zoomIn')"
|
||||
placement="top"
|
||||
>
|
||||
<div class="btn el-icon-plus" @click="enlarge"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="快捷键">
|
||||
<Sidebar ref="sidebar" :title="$t('shortcutKey.title')">
|
||||
<div class="box">
|
||||
<div v-for="item in shortcutKeyList" :key="item.type">
|
||||
<div class="title">{{ item.type }}</div>
|
||||
@@ -22,6 +22,7 @@
|
||||
<script>
|
||||
import Sidebar from './Sidebar'
|
||||
import { shortcutKeyList } from '@/config'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -34,17 +35,23 @@ export default {
|
||||
Sidebar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
shortcutKeyList
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['activeSidebar']),
|
||||
|
||||
shortcutKeyList() {
|
||||
return shortcutKeyList[this.$i18n.locale] || shortcutKeyList.zh
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('showShortcutKey', () => {
|
||||
this.$refs.sidebar.show = false
|
||||
this.$nextTick(() => {
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'shortcutKey') {
|
||||
this.$refs.sidebar.show = true
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:class="{ show: show }"
|
||||
:style="{ zIndex: zIndex }"
|
||||
>
|
||||
<span class="closeBtn el-icon-close" @click="show = false"></span>
|
||||
<span class="closeBtn el-icon-close" @click="close"></span>
|
||||
<div class="sidebarHeader" v-if="title">
|
||||
{{ title }}
|
||||
</div>
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
<script>
|
||||
import { store } from '@/config'
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -43,6 +44,14 @@ export default {
|
||||
this.zIndex = store.sidebarZIndex++
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setActiveSidebar']),
|
||||
|
||||
close() {
|
||||
this.show = false
|
||||
this.setActiveSidebar('')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
107
web/src/pages/Edit/components/SidebarTrigger.vue
Normal file
107
web/src/pages/Edit/components/SidebarTrigger.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div
|
||||
class="sidebarTriggerContainer"
|
||||
@click.stop
|
||||
:class="{ show: activeSidebar }"
|
||||
>
|
||||
<div class="trigger">
|
||||
<div
|
||||
class="triggerItem"
|
||||
v-for="item in triggerList"
|
||||
:key="item.value"
|
||||
:class="{ active: activeSidebar === item.value }"
|
||||
@click="trigger(item)"
|
||||
>
|
||||
<div class="triggerIcon iconfont" :class="[item.icon]"></div>
|
||||
<div class="triggerName">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import { sidebarTriggerList } from '@/config'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-06-24 22:54:25
|
||||
* @Desc: 侧边栏触发器
|
||||
*/
|
||||
export default {
|
||||
name: 'SidebarTrigger',
|
||||
data() {
|
||||
return {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['activeSidebar']),
|
||||
|
||||
triggerList() {
|
||||
return sidebarTriggerList[this.$i18n.locale] || sidebarTriggerList.zh
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setActiveSidebar']),
|
||||
|
||||
trigger(item) {
|
||||
this.setActiveSidebar(item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sidebarTriggerContainer {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
margin-top: 110px;
|
||||
transition: all 0.3s;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
&.show {
|
||||
right: 305px;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
width: 60px;
|
||||
border-color: #eee;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.06);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
.triggerItem {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
color: #464646;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background-color: #ededed;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #409eff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.triggerIcon {
|
||||
font-size: 18px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.triggerName {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="结构">
|
||||
<Sidebar ref="sidebar" :title="$t('strusture.title')">
|
||||
<div class="layoutList">
|
||||
<div
|
||||
class="layoutItem"
|
||||
@@ -21,6 +21,7 @@
|
||||
import Sidebar from './Sidebar'
|
||||
import { layoutList } from 'simple-mind-map/src/utils/constant'
|
||||
import { storeConfig } from '@/api'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -43,14 +44,18 @@ export default {
|
||||
layout: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('showStructure', () => {
|
||||
this.$refs.sidebar.show = false
|
||||
this.$nextTick(() => {
|
||||
computed: {
|
||||
...mapState(['activeSidebar'])
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'structure') {
|
||||
this.layout = this.mindMap.getLayout()
|
||||
this.$refs.sidebar.show = true
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="节点样式">
|
||||
<div class="styleBox">
|
||||
<Sidebar ref="sidebar" :title="$t('style.title')">
|
||||
<div class="styleBox" v-if="activeNodes.length > 0">
|
||||
<el-tabs class="tab" v-model="activeTab" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="常态" name="normal"></el-tab-pane>
|
||||
<el-tab-pane label="选中状态" name="active"></el-tab-pane>
|
||||
<el-tab-pane :label="$t('style.normal')" name="normal"></el-tab-pane>
|
||||
<el-tab-pane :label="$t('style.active')" name="active"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="sidebarContent" v-if="activeNodes.length > 0">
|
||||
<!-- 文字 -->
|
||||
<div class="title noTop">文字</div>
|
||||
<div class="title noTop">{{ $t('style.text') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">字体</span>
|
||||
<span class="name">{{ $t('style.fontFamily') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="style.fontFamily"
|
||||
@@ -31,7 +31,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">字号</span>
|
||||
<span class="name">{{ $t('style.fontSize') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -50,7 +50,7 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">行高</span>
|
||||
<span class="name">{{ $t('style.lineHeight') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -71,7 +71,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="btnGroup">
|
||||
<el-tooltip content="颜色" placement="bottom">
|
||||
<el-tooltip :content="$t('style.color')" placement="bottom">
|
||||
<div
|
||||
class="styleBtn"
|
||||
v-popover:popover
|
||||
@@ -84,7 +84,7 @@
|
||||
></span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="加粗" placement="bottom">
|
||||
<el-tooltip :content="$t('style.addFontWeight')" placement="bottom">
|
||||
<div
|
||||
class="styleBtn"
|
||||
:class="{
|
||||
@@ -96,7 +96,7 @@
|
||||
B
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="斜体" placement="bottom">
|
||||
<el-tooltip :content="$t('style.italic')" placement="bottom">
|
||||
<div
|
||||
class="styleBtn i"
|
||||
:class="{
|
||||
@@ -108,7 +108,10 @@
|
||||
I
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="划线" placement="bottom">
|
||||
<el-tooltip
|
||||
:content="$t('style.textDecoration')"
|
||||
placement="bottom"
|
||||
>
|
||||
<div
|
||||
class="styleBtn u"
|
||||
:style="{ textDecoration: style.textDecoration || 'none' }"
|
||||
@@ -138,17 +141,23 @@
|
||||
v-model="style.textDecoration"
|
||||
@change="update('textDecoration')"
|
||||
>
|
||||
<el-radio-button label="underline">下划线</el-radio-button>
|
||||
<el-radio-button label="line-through">中划线</el-radio-button>
|
||||
<el-radio-button label="overline">上划线</el-radio-button>
|
||||
<el-radio-button label="underline">{{
|
||||
$t('style.underline')
|
||||
}}</el-radio-button>
|
||||
<el-radio-button label="line-through">{{
|
||||
$t('style.lineThrough')
|
||||
}}</el-radio-button>
|
||||
<el-radio-button label="overline">{{
|
||||
$t('style.overline')
|
||||
}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-popover>
|
||||
</div>
|
||||
<!-- 边框 -->
|
||||
<div class="title">边框</div>
|
||||
<div class="title">{{ $t('style.border') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span class="name">{{ $t('style.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover3
|
||||
@@ -168,7 +177,7 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">样式</span>
|
||||
<span class="name">{{ $t('style.style') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -189,7 +198,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">宽度</span>
|
||||
<span class="name">{{ $t('style.width') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -208,7 +217,7 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">圆角</span>
|
||||
<span class="name">{{ $t('style.borderRadius') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -228,10 +237,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 背景 -->
|
||||
<div class="title">背景</div>
|
||||
<div class="title">{{ $t('style.background') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span class="name">{{ $t('style.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover4
|
||||
@@ -249,10 +258,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 形状 -->
|
||||
<div class="title">形状</div>
|
||||
<div class="title">{{ $t('style.shape') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">形状</span>
|
||||
<span class="name">{{ $t('style.shape') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 120px"
|
||||
@@ -272,10 +281,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 线条 -->
|
||||
<div class="title">线条</div>
|
||||
<div class="title">{{ $t('style.line') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span class="name">{{ $t('style.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover5
|
||||
@@ -292,7 +301,7 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">样式</span>
|
||||
<span class="name">{{ $t('style.style') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -313,7 +322,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">宽度</span>
|
||||
<span class="name">{{ $t('style.width') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
@@ -333,10 +342,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点内边距 -->
|
||||
<div class="title noTop">节点内边距</div>
|
||||
<div class="title noTop">{{ $t('style.nodePadding') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">水平</span>
|
||||
<span class="name">{{ $t('style.horizontal') }}</span>
|
||||
<el-slider
|
||||
style="width: 200px"
|
||||
v-model="style.paddingX"
|
||||
@@ -347,7 +356,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">垂直</span>
|
||||
<span class="name">{{ $t('style.vertical') }}</span>
|
||||
<el-slider
|
||||
style="width: 200px"
|
||||
v-model="style.paddingY"
|
||||
@@ -358,6 +367,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tipBox" v-else>
|
||||
<div class="tipIcon iconfont icontianjiazijiedian"></div>
|
||||
<div class="tipText">请选择一个节点</div>
|
||||
</div>
|
||||
</Sidebar>
|
||||
</template>
|
||||
|
||||
@@ -374,6 +387,7 @@ import {
|
||||
shapeList
|
||||
} from '@/config'
|
||||
import { supportActiveStyle } from 'simple-mind-map/src/themes/default'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -389,11 +403,10 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
supportActiveStyle,
|
||||
shapeList,
|
||||
fontFamilyList,
|
||||
|
||||
fontSizeList,
|
||||
borderWidthList,
|
||||
borderDasharrayList,
|
||||
|
||||
borderRadiusList,
|
||||
lineHeightList,
|
||||
activeNodes: [],
|
||||
@@ -420,19 +433,48 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['activeSidebar']),
|
||||
|
||||
fontFamilyList() {
|
||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||
},
|
||||
borderDasharrayList() {
|
||||
return borderDasharrayList[this.$i18n.locale] || borderDasharrayList.zh
|
||||
},
|
||||
shapeList() {
|
||||
return shapeList[this.$i18n.locale] || shapeList.zh
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'nodeStyle') {
|
||||
this.$refs.sidebar.show = true
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('node_active', (...args) => {
|
||||
if (this.$refs.sidebar) this.$refs.sidebar.show = false
|
||||
this.$bus.$on('node_active', this.onNodeActive)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('node_active', this.onNodeActive)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:16:21
|
||||
* @Desc: 监听节点激活事件
|
||||
*/
|
||||
onNodeActive(...args) {
|
||||
this.$nextTick(() => {
|
||||
this.activeTab = 'normal'
|
||||
this.activeNodes = args[1]
|
||||
if (this.$refs.sidebar)
|
||||
this.$refs.sidebar.show = this.activeNodes.length > 0
|
||||
this.initNodeStyle()
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2021-05-05 11:42:32
|
||||
@@ -587,6 +629,20 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.tipBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #666;
|
||||
|
||||
.tipIcon {
|
||||
font-size: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebarContent {
|
||||
padding: 20px;
|
||||
padding-top: 10px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Sidebar ref="sidebar" title="主题">
|
||||
<Sidebar ref="sidebar" :title="$t('style.title')">
|
||||
<div class="themeList">
|
||||
<div
|
||||
class="themeItem"
|
||||
@@ -21,6 +21,7 @@
|
||||
import Sidebar from './Sidebar'
|
||||
import { themeList } from 'simple-mind-map/src/utils/constant'
|
||||
import { storeConfig } from '@/api'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -43,14 +44,18 @@ export default {
|
||||
theme: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('showTheme', () => {
|
||||
this.$refs.sidebar.show = false
|
||||
this.$nextTick(() => {
|
||||
computed: {
|
||||
...mapState(['activeSidebar'])
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
if (val === 'theme') {
|
||||
this.theme = this.mindMap.getTheme()
|
||||
this.$refs.sidebar.show = true
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$refs.sidebar.show = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@click="$bus.$emit('execCommand', 'BACK')"
|
||||
>
|
||||
<span class="icon iconfont iconhoutui-shi"></span>
|
||||
<span class="text">回退</span>
|
||||
<span class="text">{{ $t('toolbar.undo') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -21,7 +21,7 @@
|
||||
@click="$bus.$emit('execCommand', 'FORWARD')"
|
||||
>
|
||||
<span class="icon iconfont iconqianjin1"></span>
|
||||
<span class="text">前进</span>
|
||||
<span class="text">{{ $t('toolbar.redo') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -31,7 +31,7 @@
|
||||
@click="$bus.$emit('execCommand', 'INSERT_NODE')"
|
||||
>
|
||||
<span class="icon iconfont iconjiedian"></span>
|
||||
<span class="text">插入同级节点</span>
|
||||
<span class="text">{{ $t('toolbar.insertSiblingNode') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -41,7 +41,7 @@
|
||||
@click="$bus.$emit('execCommand', 'INSERT_CHILD_NODE')"
|
||||
>
|
||||
<span class="icon iconfont icontianjiazijiedian"></span>
|
||||
<span class="text">插入子节点</span>
|
||||
<span class="text">{{ $t('toolbar.insertChildNode') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -51,7 +51,7 @@
|
||||
@click="$bus.$emit('execCommand', 'REMOVE_NODE')"
|
||||
>
|
||||
<span class="icon iconfont iconshanchu"></span>
|
||||
<span class="text">删除节点</span>
|
||||
<span class="text">{{ $t('toolbar.deleteNode') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -61,7 +61,7 @@
|
||||
@click="$bus.$emit('showNodeImage')"
|
||||
>
|
||||
<span class="icon iconfont iconimage"></span>
|
||||
<span class="text">图片</span>
|
||||
<span class="text">{{ $t('toolbar.image') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -71,7 +71,7 @@
|
||||
@click="$bus.$emit('showNodeIcon')"
|
||||
>
|
||||
<span class="icon iconfont iconxiaolian"></span>
|
||||
<span class="text">图标</span>
|
||||
<span class="text">{{ $t('toolbar.icon') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -81,7 +81,7 @@
|
||||
@click="$bus.$emit('showNodeLink')"
|
||||
>
|
||||
<span class="icon iconfont iconchaolianjie"></span>
|
||||
<span class="text">超链接</span>
|
||||
<span class="text">{{ $t('toolbar.link') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -91,7 +91,7 @@
|
||||
@click="$bus.$emit('showNodeNote')"
|
||||
>
|
||||
<span class="icon iconfont iconflow-Mark"></span>
|
||||
<span class="text">备注</span>
|
||||
<span class="text">{{ $t('toolbar.note') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -101,7 +101,7 @@
|
||||
@click="$bus.$emit('showNodeTag')"
|
||||
>
|
||||
<span class="icon iconfont iconbiaoqian"></span>
|
||||
<span class="text">标签</span>
|
||||
<span class="text">{{ $t('toolbar.tag') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="toolbarBtn"
|
||||
@@ -111,53 +111,30 @@
|
||||
@click="$bus.$emit('execCommand', 'ADD_GENERALIZATION')"
|
||||
>
|
||||
<span class="icon iconfont icongaikuozonglan"></span>
|
||||
<span class="text">概要</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 通用操作 -->
|
||||
<div class="toolbarBlock">
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showOutline')">
|
||||
<span class="icon iconfont iconfuhao-dagangshu"></span>
|
||||
<span class="text">显示大纲</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showBaseStyle')">
|
||||
<span class="icon iconfont iconyangshi"></span>
|
||||
<span class="text">基础样式</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showTheme')">
|
||||
<span class="icon iconfont iconjingzi"></span>
|
||||
<span class="text">主题</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showStructure')">
|
||||
<span class="icon iconfont iconjiegou"></span>
|
||||
<span class="text">结构</span>
|
||||
<span class="text">{{ $t('toolbar.summary') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 导出 -->
|
||||
<div class="toolbarBlock">
|
||||
<div class="toolbarBtn" @click="createNewLocalFile">
|
||||
<span class="icon iconfont iconxinjian"></span>
|
||||
<span class="text">新建</span>
|
||||
<span class="text">{{ $t('toolbar.newFile') }}</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="openLocalFile">
|
||||
<span class="icon iconfont icondakai"></span>
|
||||
<span class="text">打开</span>
|
||||
<span class="text">{{ $t('toolbar.openFile') }}</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="saveLocalFile">
|
||||
<span class="icon iconfont iconlingcunwei"></span>
|
||||
<span class="text">另存为</span>
|
||||
<span class="text">{{ $t('toolbar.saveAs') }}</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showImport')">
|
||||
<span class="icon iconfont icondaoru"></span>
|
||||
<span class="text">导入</span>
|
||||
<span class="text">{{ $t('toolbar.import') }}</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showExport')">
|
||||
<span class="icon iconfont iconexport"></span>
|
||||
<span class="text">导出</span>
|
||||
</div>
|
||||
<div class="toolbarBtn" @click="$bus.$emit('showShortcutKey')">
|
||||
<span class="icon iconfont iconjianpan"></span>
|
||||
<span class="text">快捷键</span>
|
||||
<span class="text">{{ $t('toolbar.export') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,24 +213,58 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('mode_change', mode => {
|
||||
this.$bus.$on('mode_change', this.onModeChange)
|
||||
this.$bus.$on('node_active', this.onNodeActive)
|
||||
this.$bus.$on('back_forward', this.onBackForward)
|
||||
this.$bus.$on('write_local_file', this.onWriteLocalFile)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('mode_change', this.onModeChange)
|
||||
this.$bus.$off('node_active', this.onNodeActive)
|
||||
this.$bus.$off('back_forward', this.onBackForward)
|
||||
this.$bus.$off('write_local_file', this.onWriteLocalFile)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:17:40
|
||||
* @Desc: 监听模式切换
|
||||
*/
|
||||
onModeChange(mode) {
|
||||
this.readonly = mode === 'readonly'
|
||||
})
|
||||
this.$bus.$on('node_active', (...args) => {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:18:06
|
||||
* @Desc: 监听节点激活
|
||||
*/
|
||||
onNodeActive(...args) {
|
||||
this.activeNodes = args[1]
|
||||
})
|
||||
this.$bus.$on('back_forward', (index, len) => {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:18:31
|
||||
* @Desc: 监听前进后退
|
||||
*/
|
||||
onBackForward(index, len) {
|
||||
this.backEnd = index <= 0
|
||||
this.forwardEnd = index >= len - 1
|
||||
})
|
||||
this.$bus.$on('write_local_file', content => {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林25
|
||||
* @Date: 2022-11-14 19:19:14
|
||||
* @Desc: 监听本地文件读写
|
||||
*/
|
||||
onWriteLocalFile(content) {
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.writeLocalFile(content)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
* @Date: 2022-09-24 15:40:09
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user