mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-22 09:10:29 +08:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a64094f14 | ||
|
|
95fdb35f7b | ||
|
|
497c2606df | ||
|
|
d735be1204 | ||
|
|
45d2da1337 | ||
|
|
194571d5fe | ||
|
|
418b24b039 | ||
|
|
b32a8b5a85 | ||
|
|
2dee415a64 | ||
|
|
4e7d59b328 | ||
|
|
9bde9ffaf3 | ||
|
|
1b4ca19ad8 | ||
|
|
eb72e0eed3 | ||
|
|
6dea1ef9b2 | ||
|
|
c6c1ef2117 | ||
|
|
4423fd562b | ||
|
|
7b1ea5e354 | ||
|
|
5192753816 | ||
|
|
6382e8acd8 | ||
|
|
e293039b3c | ||
|
|
f819cbc5b1 | ||
|
|
44a883c473 | ||
|
|
c1f600dc1f | ||
|
|
4777ab3e58 | ||
|
|
12c6479c0d | ||
|
|
f79918ec6f | ||
|
|
ba9a6e501a | ||
|
|
9b55d051dc | ||
|
|
159a4a202c | ||
|
|
ac72c0c1dc | ||
|
|
f54f92c303 | ||
|
|
c2dbfb41d5 | ||
|
|
5867649429 | ||
|
|
de29ec59c5 |
28
README.md
28
README.md
@@ -25,6 +25,8 @@ Github:[releases](https://github.com/wanglin2/mind-map/releases)。百度云
|
||||
|
||||
> 客户端版本会落后于在线版本,尝试最新功能请优先使用在线版。
|
||||
|
||||
【云存储版本】如果你需要带后端的云存储版本,可以尝试我们开发的另一个项目[理想文档](https://github.com/wanglin2/lx-doc)。
|
||||
|
||||
# 特性
|
||||
|
||||
- [x] 插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积
|
||||
@@ -35,7 +37,7 @@ Github:[releases](https://github.com/wanglin2/mind-map/releases)。百度云
|
||||
- [x] 支持画布拖动、缩放
|
||||
- [x] 支持鼠标按键拖动选择和 Ctrl+左键两种多选节点方式
|
||||
- [x] 支持导出为`json`、`png`、`svg`、`pdf`、`markdown`、`xmind`、`txt`,支持从`json`、`xmind`、`markdown`导入
|
||||
- [x] 支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条、手绘风格、彩虹线条
|
||||
- [x] 支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条、手绘风格、彩虹线条、标记、外框
|
||||
- [x] 提供丰富的配置,满足各种场景各种使用习惯
|
||||
- [x] 支持协同编辑
|
||||
- [x] 支持演示模式
|
||||
@@ -413,4 +415,28 @@ const mindMap = new MindMap({
|
||||
<img src="./web/src/assets/avatar/buddy.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>buddy</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/default.png" style="width: 50px;height: 50px;" />
|
||||
<span>小川</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/Tobin.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>Tobin</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/夏虫不语冰.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>夏虫不语冰</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/晴空.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>晴空</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/default.png" style="width: 50px;height: 50px;" />
|
||||
<span>黄泳</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/ccccs.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>ccccs</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
File diff suppressed because one or more lines are too long
BIN
dist/fonts/KaTeX_AMS-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_AMS-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_AMS-Regular.woff
vendored
BIN
dist/fonts/KaTeX_AMS-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_AMS-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_AMS-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Bold.ttf
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Bold.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Bold.woff
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Bold.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Bold.woff2
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Bold.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Caligraphic-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Caligraphic-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Bold.ttf
vendored
BIN
dist/fonts/KaTeX_Fraktur-Bold.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Bold.woff
vendored
BIN
dist/fonts/KaTeX_Fraktur-Bold.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Bold.woff2
vendored
BIN
dist/fonts/KaTeX_Fraktur-Bold.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Fraktur-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Fraktur-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Fraktur-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Fraktur-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Bold.ttf
vendored
BIN
dist/fonts/KaTeX_Main-Bold.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Bold.woff
vendored
BIN
dist/fonts/KaTeX_Main-Bold.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Bold.woff2
vendored
BIN
dist/fonts/KaTeX_Main-Bold.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-BoldItalic.ttf
vendored
BIN
dist/fonts/KaTeX_Main-BoldItalic.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-BoldItalic.woff
vendored
BIN
dist/fonts/KaTeX_Main-BoldItalic.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-BoldItalic.woff2
vendored
BIN
dist/fonts/KaTeX_Main-BoldItalic.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Italic.ttf
vendored
BIN
dist/fonts/KaTeX_Main-Italic.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Italic.woff
vendored
BIN
dist/fonts/KaTeX_Main-Italic.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Italic.woff2
vendored
BIN
dist/fonts/KaTeX_Main-Italic.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Main-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Main-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Main-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Main-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-BoldItalic.ttf
vendored
BIN
dist/fonts/KaTeX_Math-BoldItalic.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-BoldItalic.woff
vendored
BIN
dist/fonts/KaTeX_Math-BoldItalic.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-BoldItalic.woff2
vendored
BIN
dist/fonts/KaTeX_Math-BoldItalic.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-Italic.ttf
vendored
BIN
dist/fonts/KaTeX_Math-Italic.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-Italic.woff
vendored
BIN
dist/fonts/KaTeX_Math-Italic.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Math-Italic.woff2
vendored
BIN
dist/fonts/KaTeX_Math-Italic.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Bold.ttf
vendored
BIN
dist/fonts/KaTeX_SansSerif-Bold.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Bold.woff
vendored
BIN
dist/fonts/KaTeX_SansSerif-Bold.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Bold.woff2
vendored
BIN
dist/fonts/KaTeX_SansSerif-Bold.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Italic.ttf
vendored
BIN
dist/fonts/KaTeX_SansSerif-Italic.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Italic.woff
vendored
BIN
dist/fonts/KaTeX_SansSerif-Italic.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Italic.woff2
vendored
BIN
dist/fonts/KaTeX_SansSerif-Italic.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_SansSerif-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Regular.woff
vendored
BIN
dist/fonts/KaTeX_SansSerif-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_SansSerif-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_SansSerif-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Script-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Script-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Script-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Script-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Script-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Script-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size1-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Size1-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size1-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Size1-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size1-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Size1-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size2-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Size2-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size2-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Size2-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size2-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Size2-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size3-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Size3-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size3-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Size3-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size4-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Size4-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size4-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Size4-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Size4-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Size4-Regular.woff2
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Typewriter-Regular.ttf
vendored
BIN
dist/fonts/KaTeX_Typewriter-Regular.ttf
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Typewriter-Regular.woff
vendored
BIN
dist/fonts/KaTeX_Typewriter-Regular.woff
vendored
Binary file not shown.
BIN
dist/fonts/KaTeX_Typewriter-Regular.woff2
vendored
BIN
dist/fonts/KaTeX_Typewriter-Regular.woff2
vendored
Binary file not shown.
BIN
dist/img/Tobin.jpg
vendored
Normal file
BIN
dist/img/Tobin.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
dist/img/ccccs.jpg
vendored
Normal file
BIN
dist/img/ccccs.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
dist/img/夏虫不语冰.jpg
vendored
Normal file
BIN
dist/img/夏虫不语冰.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
dist/img/晴空.jpg
vendored
Normal file
BIN
dist/img/晴空.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
2
dist/js/app.js
vendored
2
dist/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0afe0d.js
vendored
2
dist/js/chunk-2d0afe0d.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0c0a44.js
vendored
2
dist/js/chunk-2d0c0a44.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0d9fbc.js
vendored
2
dist/js/chunk-2d0d9fbc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0dad5f.js
vendored
2
dist/js/chunk-2d0dad5f.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0e9802.js
vendored
2
dist/js/chunk-2d0e9802.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d0f026c.js
vendored
2
dist/js/chunk-2d0f026c.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d208ffa.js
vendored
2
dist/js/chunk-2d208ffa.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-2d20f68f.js
vendored
1
dist/js/chunk-2d20f68f.js
vendored
@@ -1 +0,0 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d20f68f"],{b407:function(n,u,t){"use strict";t.r(u);var c=function(){var n=this,u=n._self._c;return u("div")},e=[],l={},s=l,i=t("2877"),o=Object(i["a"])(s,c,e,!1,null,null,null);u["default"]=o.exports}}]);
|
||||
2
dist/js/chunk-2d216004.js
vendored
2
dist/js/chunk-2d216004.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d2160a3.js
vendored
2
dist/js/chunk-2d2160a3.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d21e399.js
vendored
2
dist/js/chunk-2d21e399.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/chunk-2d229d67.js
vendored
2
dist/js/chunk-2d229d67.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-428b560e.js
vendored
1
dist/js/chunk-428b560e.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-583efa32.js
vendored
Normal file
1
dist/js/chunk-583efa32.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
dist/js/chunk-68de956c.js
vendored
2
dist/js/chunk-68de956c.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-6f12c8fe.js
vendored
Normal file
1
dist/js/chunk-6f12c8fe.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/js/chunk-6fd88c2d.js
vendored
1
dist/js/chunk-6fd88c2d.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/js/chunk-cba4e134.js
vendored
Normal file
1
dist/js/chunk-cba4e134.js
vendored
Normal file
File diff suppressed because one or more lines are too long
16
index.html
16
index.html
@@ -1,11 +1,15 @@
|
||||
<!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,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><link rel="icon" href="dist/logo.ico"><title>思绪思维导图</title><script>// 自定义静态资源的路径
|
||||
window.externalPublicPath = './dist/'
|
||||
// 接管应用
|
||||
window.takeOverApp = false</script><script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script><script>LA.init({
|
||||
id: 'KRO0WxK8GT66tYCQ',
|
||||
ck: 'KRO0WxK8GT66tYCQ',
|
||||
autoTrack: false
|
||||
})</script><link href="dist/css/chunk-vendors.css?dd8fa3cd99060d550179" rel="stylesheet"><link href="dist/css/app.css?dd8fa3cd99060d550179" 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>const getDataFromBackend = () => {
|
||||
window.takeOverApp = false</script><script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script><script>try {
|
||||
LA.init({
|
||||
id: 'KRO0WxK8GT66tYCQ',
|
||||
ck: 'KRO0WxK8GT66tYCQ',
|
||||
autoTrack: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}</script><link href="dist/css/chunk-vendors.css?4d8e2833c3860a9a5265" rel="stylesheet"><link href="dist/css/app.css?4d8e2833c3860a9a5265" 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>const getDataFromBackend = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
@@ -70,4 +74,4 @@
|
||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||
// 实例化页面
|
||||
window.initApp()
|
||||
}</script><script src="dist/js/chunk-vendors.js?dd8fa3cd99060d550179"></script><script src="dist/js/app.js?dd8fa3cd99060d550179"></script></body></html>
|
||||
}</script><script src="dist/js/chunk-vendors.js?4d8e2833c3860a9a5265"></script><script src="dist/js/app.js?4d8e2833c3860a9a5265"></script></body></html>
|
||||
@@ -31,7 +31,7 @@ MindMap.iconList = icons.nodeIconList
|
||||
MindMap.constants = constants
|
||||
MindMap.themes = themes
|
||||
MindMap.defaultTheme = defaultTheme
|
||||
MindMap.version = '0.10.2'
|
||||
MindMap.version = '0.10.4'
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
|
||||
@@ -194,7 +194,7 @@ class MindMap {
|
||||
this.renderer.reRender = true // 标记为重新渲染
|
||||
this.renderer.clearCache() // 清空节点缓存池
|
||||
this.clearDraw() // 清空画布
|
||||
this.render(callback, (source = ''))
|
||||
this.render(callback, source)
|
||||
}
|
||||
|
||||
// 获取或更新容器尺寸位置信息
|
||||
@@ -288,7 +288,9 @@ class MindMap {
|
||||
|
||||
// 更新配置
|
||||
updateConfig(opt = {}) {
|
||||
this.emit('before_update_config', this.opt)
|
||||
this.opt = this.handleOpt(merge.all([defaultOpt, this.opt, opt]))
|
||||
this.emit('after_update_config', this.opt)
|
||||
}
|
||||
|
||||
// 获取当前布局结构
|
||||
@@ -379,6 +381,9 @@ class MindMap {
|
||||
// 导出
|
||||
async export(...args) {
|
||||
try {
|
||||
if (!this.doExport) {
|
||||
throw new Error('请注册Export插件!')
|
||||
}
|
||||
let result = await this.doExport.export(...args)
|
||||
return result
|
||||
} catch (error) {
|
||||
@@ -416,6 +421,11 @@ class MindMap {
|
||||
addContentToFooter,
|
||||
node
|
||||
} = {}) {
|
||||
const { watermarkConfig, openPerformance } = this.opt
|
||||
// 如果开启了性能模式,那么需要先渲染所有节点
|
||||
if (openPerformance) {
|
||||
this.renderer.forceLoadNode(node)
|
||||
}
|
||||
const { cssTextList, header, headerHeight, footer, footerHeight } =
|
||||
handleGetSvgDataExtraContent({
|
||||
addContentToHeader,
|
||||
@@ -459,7 +469,7 @@ class MindMap {
|
||||
if (!ignoreWatermark && hasWatermark) {
|
||||
this.watermark.isInExport = true
|
||||
// 是否是仅导出时需要水印
|
||||
const { onlyExport } = this.opt.watermarkConfig
|
||||
const { onlyExport } = watermarkConfig
|
||||
// 是否需要重新绘制水印
|
||||
const needReDrawWatermark =
|
||||
rect.width > origWidth || rect.height > origHeight
|
||||
|
||||
6
simple-mind-map/package-lock.json
generated
6
simple-mind-map/package-lock.json
generated
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.10.0-fix.1",
|
||||
"version": "0.10.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "0.10.0-fix.1",
|
||||
"version": "0.10.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@svgdotjs/svg.js": "^3.0.16",
|
||||
"@svgdotjs/svg.js": "^3.2.0",
|
||||
"deepmerge": "^1.5.2",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"jszip": "^3.10.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.10.2",
|
||||
"version": "0.10.4",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
@@ -28,7 +28,7 @@
|
||||
"module": "index.js",
|
||||
"main": "./dist/simpleMindMap.umd.min.js",
|
||||
"dependencies": {
|
||||
"@svgdotjs/svg.js": "^3.0.16",
|
||||
"@svgdotjs/svg.js": "^3.2.0",
|
||||
"deepmerge": "^1.5.2",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"jszip": "^3.10.1",
|
||||
|
||||
@@ -235,6 +235,10 @@ export const CONSTANTS = {
|
||||
DEFAULT: 'default',
|
||||
NOT_ACTIVE: 'notActive',
|
||||
ACTIVE_ONLY: 'activeOnly'
|
||||
},
|
||||
TAG_POSITION: {
|
||||
RIGHT: 'right',
|
||||
BOTTOM: 'bottom'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ export const defaultOpt = {
|
||||
mouseScaleCenterUseMousePosition: true,
|
||||
// 最多显示几个标签
|
||||
maxTag: 5,
|
||||
// 标签显示的位置,相对于节点文本,bottom(下方)、right(右侧)
|
||||
tagPosition: CONSTANTS.TAG_POSITION.RIGHT,
|
||||
// 展开收缩按钮尺寸
|
||||
expandBtnSize: 20,
|
||||
// 节点里图片和文字的间距
|
||||
@@ -226,6 +228,14 @@ export const defaultOpt = {
|
||||
// 自定义超链接的跳转
|
||||
// 如果不传,默认会以新窗口的方式打开超链接,可以传递一个函数,函数接收两个参数:link(超链接的url)、node(所属节点实例),只要传递了函数,就会阻止默认的跳转
|
||||
customHyperlinkJump: null,
|
||||
// 是否开启性能模式,默认情况下所有节点都会直接渲染,无论是否处于画布可视区域,这样当节点数量比较多时(1000+)会比较卡,如果你的数据量比较大,那么可以通过该配置开启性能模式,即只渲染画布可视区域内的节点,超出的节点不渲染,这样会大幅提高渲染速度,当然同时也会带来一些其他问题,比如:1.当拖动或是缩放画布时会实时计算并渲染未节点的节点,所以会带来一定卡顿;2.导出图片、svg、pdf时需要先渲染全部节点,所以会比较慢;3.其他目前未发现的问题
|
||||
openPerformance: false,
|
||||
// 性能优化模式配置
|
||||
performanceConfig: {
|
||||
time: 250,// 当视图改变后多久刷新一次节点,单位:ms,
|
||||
padding: 100,// 超出画布四周指定范围内依旧渲染节点
|
||||
removeNodeWhenOutCanvas: true,// 节点移除画布可视区域后从画布删除
|
||||
},
|
||||
|
||||
// 【Select插件】
|
||||
// 多选节点时鼠标移动到边缘时的画布移动偏移量
|
||||
@@ -379,6 +389,12 @@ export const defaultOpt = {
|
||||
// 【Formula插件】
|
||||
// 是否开启在富文本编辑框中直接编辑数学公式
|
||||
enableEditFormulaInRichTextEdit: true,
|
||||
// katex库的字体文件的请求路径。仅当katex的output配置为html时才会请求字体文件。可以通过mindMap.formula.getKatexConfig()方法来获取当前的配置
|
||||
// 字体文件可以从node_modules中找到:katex/dist/fonts/。可以上传到你的服务器或cdn
|
||||
// 最终的字体请求路径为`${katexFontPath}fonts/KaTeX_AMS-Regular.woff2`,可以自行拼接进行测试是否可以访问
|
||||
katexFontPath: 'https://unpkg.com/katex@0.16.11/dist/',
|
||||
// 自定义katex库的输出模式。默认当Chrome内核100以下会使用html方式,否则使用mathml方式,如果你有自己的规则,那么可以传递一个函数,函数返回值为:mathml或html
|
||||
getKatexOutputType: null,
|
||||
|
||||
// 【RichText插件】
|
||||
// 转换富文本内容,当进入富文本编辑时,可以通过该参数传递一个函数,函数接收文本内容,需要返回你处理后的文本内容
|
||||
@@ -387,5 +403,9 @@ export const defaultOpt = {
|
||||
beforeHideRichTextEdit: null,
|
||||
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
|
||||
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果
|
||||
richTextEditFakeInPlace: false
|
||||
richTextEditFakeInPlace: false,
|
||||
|
||||
// 【OuterFrame】插件
|
||||
outerFramePaddingX: 10,
|
||||
outerFramePaddingY: 10
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ import {
|
||||
checkSmmFormatData,
|
||||
checkIsNodeStyleDataKey,
|
||||
removeRichTextStyes,
|
||||
formatGetNodeGeneralization
|
||||
formatGetNodeGeneralization,
|
||||
sortNodeList,
|
||||
throttle
|
||||
} from '../../utils'
|
||||
import { shapeList } from './node/Shape'
|
||||
import { lineStyleProps } from '../../themes/default'
|
||||
@@ -143,13 +145,54 @@ class Render {
|
||||
if (!this.mindMap.opt.enableDblclickBackToRootNode) return
|
||||
this.setRootNodeCenter()
|
||||
})
|
||||
// let timer = null
|
||||
// this.mindMap.on('view_data_change', () => {
|
||||
// clearTimeout(timer)
|
||||
// timer = setTimeout(() => {
|
||||
// this.render()
|
||||
// }, 300)
|
||||
// })
|
||||
// 性能模式
|
||||
this.performanceMode()
|
||||
}
|
||||
|
||||
// 性能模式,懒加载节点
|
||||
performanceMode() {
|
||||
const { openPerformance, performanceConfig } = this.mindMap.opt
|
||||
const onViewDataChange = throttle(() => {
|
||||
if (this.root) {
|
||||
this.mindMap.emit('node_tree_render_start')
|
||||
this.root.render(
|
||||
() => {
|
||||
this.mindMap.emit('node_tree_render_end')
|
||||
},
|
||||
false,
|
||||
true
|
||||
)
|
||||
}
|
||||
}, performanceConfig.time)
|
||||
let lastOpen = false
|
||||
this.mindMap.on('before_update_config', opt => {
|
||||
lastOpen = opt.openPerformance
|
||||
})
|
||||
this.mindMap.on('after_update_config', opt => {
|
||||
if (opt.openPerformance && !lastOpen) {
|
||||
// 动态开启性能模式
|
||||
this.mindMap.on('view_data_change', onViewDataChange)
|
||||
this.forceLoadNode()
|
||||
}
|
||||
if (!opt.openPerformance && lastOpen) {
|
||||
// 动态关闭性能模式
|
||||
this.mindMap.off('view_data_change', onViewDataChange)
|
||||
this.forceLoadNode()
|
||||
}
|
||||
})
|
||||
if (!openPerformance) return
|
||||
this.mindMap.on('view_data_change', onViewDataChange)
|
||||
}
|
||||
|
||||
// 强制渲染节点,不考虑是否在画布可视区域内
|
||||
forceLoadNode(node) {
|
||||
node = node || this.root
|
||||
if (node) {
|
||||
this.mindMap.emit('node_tree_render_start')
|
||||
node.render(() => {
|
||||
this.mindMap.emit('node_tree_render_end')
|
||||
}, true)
|
||||
}
|
||||
}
|
||||
|
||||
// 注册命令
|
||||
@@ -452,6 +495,7 @@ class Render {
|
||||
}
|
||||
this.mindMap.emit('node_tree_render_start')
|
||||
// 计算布局
|
||||
this.root = null
|
||||
this.layout.doLayout(root => {
|
||||
// 删除本次渲染时不再需要的节点
|
||||
Object.keys(this.lastNodeCache).forEach(uid => {
|
||||
@@ -1373,7 +1417,8 @@ class Render {
|
||||
if (this.activeNodeList.length <= 0) {
|
||||
return null
|
||||
}
|
||||
const nodeList = getTopAncestorsFomNodeList(this.activeNodeList)
|
||||
let nodeList = getTopAncestorsFomNodeList(this.activeNodeList)
|
||||
nodeList = sortNodeList(nodeList)
|
||||
return nodeList.map(node => {
|
||||
return copyNodeTree({}, node, true)
|
||||
})
|
||||
@@ -1385,11 +1430,12 @@ class Render {
|
||||
return
|
||||
}
|
||||
// 找出激活节点中的顶层节点列表,并过滤掉根节点
|
||||
const nodeList = getTopAncestorsFomNodeList(this.activeNodeList).filter(
|
||||
let nodeList = getTopAncestorsFomNodeList(this.activeNodeList).filter(
|
||||
node => {
|
||||
return !node.isRoot
|
||||
}
|
||||
)
|
||||
nodeList = sortNodeList(nodeList)
|
||||
// 复制数据
|
||||
const copyData = nodeList.map(node => {
|
||||
return copyNodeTree({}, node, true)
|
||||
@@ -1665,11 +1711,13 @@ class Render {
|
||||
)
|
||||
})
|
||||
const list = parseAddGeneralizationNodeList(nodeList)
|
||||
if (list.length <= 0) return
|
||||
const isRichText = !!this.mindMap.richText
|
||||
const { focusNewNode, inserting } = this.getNewNodeBehavior(
|
||||
openEdit,
|
||||
list.length > 1
|
||||
)
|
||||
let needRender = false
|
||||
list.forEach(item => {
|
||||
const newData = {
|
||||
inserting,
|
||||
@@ -1683,15 +1731,30 @@ class Render {
|
||||
isActive: focusNewNode
|
||||
}
|
||||
let generalization = item.node.getData('generalization')
|
||||
if (generalization) {
|
||||
if (Array.isArray(generalization)) {
|
||||
generalization.push(newData)
|
||||
} else {
|
||||
generalization = [generalization, newData]
|
||||
generalization = generalization
|
||||
? Array.isArray(generalization)
|
||||
? generalization
|
||||
: [generalization]
|
||||
: []
|
||||
// 如果是范围概要,那么检查该范围是否存在
|
||||
if (item.range) {
|
||||
const isExist = !!generalization.find(item2 => {
|
||||
return (
|
||||
item2.range &&
|
||||
item2.range[0] === item.range[0] &&
|
||||
item2.range[1] === item.range[1]
|
||||
)
|
||||
})
|
||||
if (isExist) {
|
||||
return
|
||||
}
|
||||
// 不存在则添加
|
||||
generalization.push(newData)
|
||||
} else {
|
||||
generalization = [newData]
|
||||
// 不是范围概要直接添加,因为前面已经判断过是否存在
|
||||
generalization.push(newData)
|
||||
}
|
||||
needRender = true
|
||||
this.mindMap.execCommand('SET_NODE_DATA', item.node, {
|
||||
generalization
|
||||
})
|
||||
@@ -1700,6 +1763,7 @@ class Render {
|
||||
expand: true
|
||||
})
|
||||
})
|
||||
if (!needRender) return
|
||||
// 需要清除原来激活的节点
|
||||
if (focusNewNode) {
|
||||
this.clearActiveNodeList()
|
||||
|
||||
@@ -187,7 +187,8 @@ export default class TextEdit {
|
||||
|
||||
// 处理画布缩放
|
||||
onScale() {
|
||||
if (!this.currentNode) return
|
||||
const node = this.getCurrentEditNode()
|
||||
if (!node) return
|
||||
if (this.mindMap.richText) {
|
||||
this.mindMap.richText.cacheEditingText =
|
||||
this.mindMap.richText.getEditText()
|
||||
@@ -197,7 +198,7 @@ export default class TextEdit {
|
||||
this.showTextEdit = false
|
||||
}
|
||||
this.show({
|
||||
node: this.currentNode,
|
||||
node,
|
||||
isFromScale: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,11 +253,15 @@ class Node {
|
||||
height: rect.height
|
||||
}
|
||||
}
|
||||
const { tagPosition } = this.mindMap.opt
|
||||
const tagIsBottom = tagPosition === CONSTANTS.TAG_POSITION.BOTTOM
|
||||
// 宽高
|
||||
let imgContentWidth = 0
|
||||
let imgContentHeight = 0
|
||||
let textContentWidth = 0
|
||||
let textContentHeight = 0
|
||||
let tagContentWidth = 0
|
||||
let tagContentHeight = 0
|
||||
// 存在图片
|
||||
if (this._imgData) {
|
||||
this._rectInfo.imgContentWidth = imgContentWidth = this._imgData.width
|
||||
@@ -290,10 +294,20 @@ class Node {
|
||||
}
|
||||
// 标签
|
||||
if (this._tagData.length > 0) {
|
||||
textContentWidth += this._tagData.reduce((sum, cur) => {
|
||||
textContentHeight = Math.max(textContentHeight, cur.height)
|
||||
let maxTagHeight = 0
|
||||
const totalTagWidth = this._tagData.reduce((sum, cur) => {
|
||||
maxTagHeight = Math.max(maxTagHeight, cur.height)
|
||||
return (sum += cur.width + this.textContentItemMargin)
|
||||
}, 0)
|
||||
if (tagIsBottom) {
|
||||
// 文字下方
|
||||
tagContentWidth = totalTagWidth
|
||||
tagContentHeight = maxTagHeight
|
||||
} else {
|
||||
// 否则在右侧
|
||||
textContentWidth += totalTagWidth
|
||||
textContentHeight = Math.max(textContentHeight, maxTagHeight)
|
||||
}
|
||||
}
|
||||
// 备注
|
||||
if (this._noteData) {
|
||||
@@ -325,6 +339,15 @@ class Node {
|
||||
// 纯内容宽高
|
||||
let _width = Math.max(imgContentWidth, textContentWidth)
|
||||
let _height = imgContentHeight + textContentHeight
|
||||
// 如果标签在文字下方
|
||||
if (tagIsBottom && tagContentHeight > 0 && textContentHeight > 0) {
|
||||
// 那么文字和标签之间也需要间距
|
||||
margin += this.blockContentMargin
|
||||
// 整体高度要考虑标签宽度
|
||||
_width = Math.max(_width, tagContentWidth)
|
||||
// 整体高度要加上标签的高度
|
||||
_height += tagContentHeight
|
||||
}
|
||||
// 计算节点形状需要的附加内边距
|
||||
let { paddingX: shapePaddingX, paddingY: shapePaddingY } =
|
||||
this.shapeInstance.getShapePadding(_width, _height, paddingX, paddingY)
|
||||
@@ -342,7 +365,7 @@ class Node {
|
||||
layout() {
|
||||
// 清除之前的内容
|
||||
this.group.clear()
|
||||
const { hoverRectPadding } = this.mindMap.opt
|
||||
const { hoverRectPadding, tagPosition } = this.mindMap.opt
|
||||
let { width, height, textContentItemMargin } = this
|
||||
let { paddingY } = this.getPaddingVale()
|
||||
const halfBorderWidth = this.getBorderWidth() / 2
|
||||
@@ -382,6 +405,8 @@ class Node {
|
||||
addHoverNode()
|
||||
return
|
||||
}
|
||||
const tagIsBottom = tagPosition === CONSTANTS.TAG_POSITION.BOTTOM
|
||||
const { textContentHeight } = this._rectInfo
|
||||
// 图片节点
|
||||
let imgHeight = 0
|
||||
if (this._imgData) {
|
||||
@@ -401,7 +426,7 @@ class Node {
|
||||
})
|
||||
foreignObject
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._prefixData.height) / 2)
|
||||
.y((textContentHeight - this._prefixData.height) / 2)
|
||||
textContentNested.add(foreignObject)
|
||||
textContentOffsetX += this._prefixData.width + textContentItemMargin
|
||||
}
|
||||
@@ -412,7 +437,7 @@ class Node {
|
||||
this._iconData.forEach(item => {
|
||||
item.node
|
||||
.x(textContentOffsetX + iconLeft)
|
||||
.y((this._rectInfo.textContentHeight - item.height) / 2)
|
||||
.y((textContentHeight - item.height) / 2)
|
||||
iconNested.add(item.node)
|
||||
iconLeft += item.width + textContentItemMargin
|
||||
})
|
||||
@@ -427,7 +452,7 @@ class Node {
|
||||
;(this._textData.nodeContent || this._textData.node)
|
||||
.x(-oldX) // 修复非富文本模式下同时存在图标和换行的文本时,被收起和展开时图标与文字距离会逐渐拉大的问题
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._textData.height) / 2)
|
||||
.y((textContentHeight - this._textData.height) / 2)
|
||||
textContentNested.add(this._textData.node)
|
||||
textContentOffsetX += this._textData.width + textContentItemMargin
|
||||
}
|
||||
@@ -435,29 +460,50 @@ class Node {
|
||||
if (this._hyperlinkData) {
|
||||
this._hyperlinkData.node
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._hyperlinkData.height) / 2)
|
||||
.y((textContentHeight - this._hyperlinkData.height) / 2)
|
||||
textContentNested.add(this._hyperlinkData.node)
|
||||
textContentOffsetX += this._hyperlinkData.width + textContentItemMargin
|
||||
}
|
||||
// 标签
|
||||
let tagNested = new G()
|
||||
if (this._tagData && this._tagData.length > 0) {
|
||||
let tagLeft = 0
|
||||
this._tagData.forEach(item => {
|
||||
item.node
|
||||
.x(textContentOffsetX + tagLeft)
|
||||
.y((this._rectInfo.textContentHeight - item.height) / 2)
|
||||
tagNested.add(item.node)
|
||||
tagLeft += item.width + textContentItemMargin
|
||||
})
|
||||
textContentNested.add(tagNested)
|
||||
textContentOffsetX += tagLeft
|
||||
if (tagIsBottom) {
|
||||
// 标签显示在文字下方
|
||||
let tagLeft = 0
|
||||
this._tagData.forEach(item => {
|
||||
item.node.x(tagLeft).y(0)
|
||||
tagNested.add(item.node)
|
||||
tagLeft += item.width + textContentItemMargin
|
||||
})
|
||||
tagNested.cx(width / 2).y(
|
||||
paddingY + // 内边距
|
||||
imgHeight + // 图片高度
|
||||
textContentHeight + // 文本区域高度
|
||||
(imgHeight > 0 && textContentHeight > 0
|
||||
? this.blockContentMargin
|
||||
: 0) + // 图片和文本之间的间距
|
||||
this.blockContentMargin // 标签和文本之间的间距
|
||||
)
|
||||
this.group.add(tagNested)
|
||||
} else {
|
||||
// 标签显示在文字右侧
|
||||
let tagLeft = 0
|
||||
this._tagData.forEach(item => {
|
||||
item.node
|
||||
.x(textContentOffsetX + tagLeft)
|
||||
.y((textContentHeight - item.height) / 2)
|
||||
tagNested.add(item.node)
|
||||
tagLeft += item.width + textContentItemMargin
|
||||
})
|
||||
textContentNested.add(tagNested)
|
||||
textContentOffsetX += tagLeft
|
||||
}
|
||||
}
|
||||
// 备注
|
||||
if (this._noteData) {
|
||||
this._noteData.node
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._noteData.height) / 2)
|
||||
.y((textContentHeight - this._noteData.height) / 2)
|
||||
textContentNested.add(this._noteData.node)
|
||||
textContentOffsetX += this._noteData.width
|
||||
}
|
||||
@@ -465,7 +511,7 @@ class Node {
|
||||
if (this._attachmentData) {
|
||||
this._attachmentData.node
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._attachmentData.height) / 2)
|
||||
.y((textContentHeight - this._attachmentData.height) / 2)
|
||||
textContentNested.add(this._attachmentData.node)
|
||||
textContentOffsetX += this._attachmentData.width
|
||||
}
|
||||
@@ -478,20 +524,18 @@ class Node {
|
||||
})
|
||||
foreignObject
|
||||
.x(textContentOffsetX)
|
||||
.y((this._rectInfo.textContentHeight - this._postfixData.height) / 2)
|
||||
.y((textContentHeight - this._postfixData.height) / 2)
|
||||
textContentNested.add(foreignObject)
|
||||
textContentOffsetX += this._postfixData.width
|
||||
}
|
||||
this.group.add(textContentNested)
|
||||
// 文字内容整体
|
||||
textContentNested.translate(
|
||||
width / 2 - textContentNested.bbox().width / 2,
|
||||
imgHeight +
|
||||
paddingY +
|
||||
(imgHeight > 0 && this._rectInfo.textContentHeight > 0
|
||||
? this.blockContentMargin
|
||||
: 0)
|
||||
paddingY + // 内边距
|
||||
imgHeight + // 图片高度
|
||||
(imgHeight > 0 && textContentHeight > 0 ? this.blockContentMargin : 0) // 和图片的间距
|
||||
)
|
||||
this.group.add(textContentNested)
|
||||
addHoverNode()
|
||||
this.mindMap.emit('node_layout_end', this)
|
||||
}
|
||||
@@ -639,7 +683,7 @@ class Node {
|
||||
}
|
||||
|
||||
// 更新节点
|
||||
update() {
|
||||
update(forceRender) {
|
||||
if (!this.group) {
|
||||
return
|
||||
}
|
||||
@@ -666,36 +710,11 @@ class Node {
|
||||
}
|
||||
}
|
||||
// 更新概要
|
||||
this.renderGeneralization()
|
||||
this.renderGeneralization(forceRender)
|
||||
// 更新协同头像
|
||||
if (this.updateUserListNode) this.updateUserListNode()
|
||||
// 更新节点位置
|
||||
let t = this.group.transform()
|
||||
// // 如果上次不在可视区内,且本次也不在,那么直接返回
|
||||
// let { left: ox, top: oy } = this.getNodePosInClient(
|
||||
// t.translateX,
|
||||
// t.translateY
|
||||
// )
|
||||
// let oldIsInClient =
|
||||
// ox > 0 && oy > 0 && ox < this.mindMap.width && oy < this.mindMap.height
|
||||
// let { left: nx, top: ny } = this.getNodePosInClient(this.left, this.top)
|
||||
// let newIsNotInClient =
|
||||
// nx + this.width < 0 ||
|
||||
// ny + this.height < 0 ||
|
||||
// nx > this.mindMap.width ||
|
||||
// ny > this.mindMap.height
|
||||
// if (!oldIsInClient && newIsNotInClient) {
|
||||
// if (!this.isHide) {
|
||||
// this.isHide = true
|
||||
// this.group.hide()
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// // 如果当前是隐藏状态,那么先显示
|
||||
// if (this.isHide) {
|
||||
// this.isHide = false
|
||||
// this.group.show()
|
||||
// }
|
||||
// 如果节点位置没有变化,则返回
|
||||
if (this.left === t.translateX && this.top === t.translateY) return
|
||||
this.group.translate(this.left - t.translateX, this.top - t.translateY)
|
||||
@@ -713,6 +732,17 @@ class Node {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断节点是否可见
|
||||
checkIsInClient(padding = 0) {
|
||||
const { left: nx, top: ny } = this.getNodePosInClient(this.left, this.top)
|
||||
return (
|
||||
nx + this.width > 0 - padding &&
|
||||
ny + this.height > 0 - padding &&
|
||||
nx < this.mindMap.width + padding &&
|
||||
ny < this.mindMap.height + padding
|
||||
)
|
||||
}
|
||||
|
||||
// 重新渲染节点,即重新创建节点内容、计算节点大小、计算节点内容布局、更新展开收起按钮,概要及位置
|
||||
reRender() {
|
||||
let sizeChange = this.getSize()
|
||||
@@ -741,32 +771,44 @@ class Node {
|
||||
}
|
||||
}
|
||||
|
||||
// 递归渲染
|
||||
render(callback = () => {}) {
|
||||
// 递归渲染
|
||||
// forceRender:强制渲染,无论是否处于画布可视区域
|
||||
// async:异步渲染
|
||||
render(callback = () => {}, forceRender = false, async = false) {
|
||||
// 节点
|
||||
// 重新渲染连线
|
||||
this.renderLine()
|
||||
if (!this.group) {
|
||||
// 创建组
|
||||
this.group = new G()
|
||||
this.group.addClass('smm-node')
|
||||
this.group.css({
|
||||
cursor: 'default'
|
||||
})
|
||||
this.bindGroupEvent()
|
||||
this.nodeDraw.add(this.group)
|
||||
this.layout()
|
||||
this.update()
|
||||
} else {
|
||||
if (!this.nodeDraw.has(this.group)) {
|
||||
const { openPerformance, performanceConfig } = this.mindMap.opt
|
||||
// 强制渲染、或没有开启性能模式、或不在画布可视区域内不渲染节点内容
|
||||
if (
|
||||
forceRender ||
|
||||
!openPerformance ||
|
||||
this.checkIsInClient(performanceConfig.padding)
|
||||
) {
|
||||
if (!this.group) {
|
||||
// 创建组
|
||||
this.group = new G()
|
||||
this.group.addClass('smm-node')
|
||||
this.group.css({
|
||||
cursor: 'default'
|
||||
})
|
||||
this.bindGroupEvent()
|
||||
this.nodeDraw.add(this.group)
|
||||
}
|
||||
if (this.needLayout) {
|
||||
this.needLayout = false
|
||||
this.layout()
|
||||
this.update(forceRender)
|
||||
} else {
|
||||
if (!this.nodeDraw.has(this.group)) {
|
||||
this.nodeDraw.add(this.group)
|
||||
}
|
||||
if (this.needLayout) {
|
||||
this.needLayout = false
|
||||
this.layout()
|
||||
}
|
||||
this.updateExpandBtnPlaceholderRect()
|
||||
this.update(forceRender)
|
||||
}
|
||||
this.updateExpandBtnPlaceholderRect()
|
||||
this.update()
|
||||
} else if (openPerformance && performanceConfig.removeNodeWhenOutCanvas) {
|
||||
this.removeSelf()
|
||||
}
|
||||
// 子节点
|
||||
if (
|
||||
@@ -776,12 +818,23 @@ class Node {
|
||||
) {
|
||||
let index = 0
|
||||
this.children.forEach(item => {
|
||||
item.render(() => {
|
||||
index++
|
||||
if (index >= this.children.length) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
const renderChild = () => {
|
||||
item.render(
|
||||
() => {
|
||||
index++
|
||||
if (index >= this.children.length) {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
forceRender,
|
||||
async
|
||||
)
|
||||
}
|
||||
if (async) {
|
||||
setTimeout(renderChild, 0)
|
||||
} else {
|
||||
renderChild()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
callback()
|
||||
@@ -796,6 +849,13 @@ class Node {
|
||||
}
|
||||
}
|
||||
|
||||
// 删除自身,只是从画布删除,节点容器还在,后续还可以重新插回画布
|
||||
removeSelf() {
|
||||
if (!this.group) return
|
||||
this.group.remove()
|
||||
this.removeGeneralization()
|
||||
}
|
||||
|
||||
// 递归删除,只是从画布删除,节点容器还在,后续还可以重新插回画布
|
||||
remove() {
|
||||
if (!this.group) return
|
||||
@@ -812,6 +872,10 @@ class Node {
|
||||
|
||||
// 销毁节点,不但会从画布删除,而且原节点直接置空,后续无法再插回画布
|
||||
destroy() {
|
||||
this.removeLine()
|
||||
if (this.parent) {
|
||||
this.parent.removeLine()
|
||||
}
|
||||
if (!this.group) return
|
||||
if (this.emptyUser) {
|
||||
this.emptyUser()
|
||||
@@ -819,11 +883,7 @@ class Node {
|
||||
this.resetWhenDelete()
|
||||
this.group.remove()
|
||||
this.removeGeneralization()
|
||||
this.removeLine()
|
||||
this.group = null
|
||||
if (this.parent) {
|
||||
this.parent.removeLine()
|
||||
}
|
||||
this.style.onRemove()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
checkIsNodeStyleDataKey,
|
||||
generateColorByContent
|
||||
} from '../../../utils/index'
|
||||
import { Gradient } from '@svgdotjs/svg.js'
|
||||
import { checkIsNodeStyleDataKey } from '../../../utils/index'
|
||||
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
const backgroundStyleProps = [
|
||||
@@ -182,21 +178,24 @@ class Style {
|
||||
}
|
||||
|
||||
// 标签文字
|
||||
tagText(node) {
|
||||
tagText(node, style) {
|
||||
node
|
||||
.fill({
|
||||
color: '#fff'
|
||||
})
|
||||
.css({
|
||||
'font-size': '12px'
|
||||
'font-size': style.fontSize + 'px'
|
||||
})
|
||||
}
|
||||
|
||||
// 标签矩形
|
||||
tagRect(node, text, color) {
|
||||
tagRect(node, style) {
|
||||
node.fill({
|
||||
color: color || generateColorByContent(text.node.textContent)
|
||||
color: style.fill
|
||||
})
|
||||
if (style.radius) {
|
||||
node.radius(style.radius)
|
||||
}
|
||||
}
|
||||
|
||||
// 内置图标
|
||||
|
||||
@@ -6,12 +6,23 @@ import {
|
||||
checkIsRichText,
|
||||
isUndef,
|
||||
createForeignObjectNode,
|
||||
addXmlns
|
||||
addXmlns,
|
||||
generateColorByContent
|
||||
} from '../../../utils'
|
||||
import { Image as SVGImage, SVG, A, G, Rect, Text } from '@svgdotjs/svg.js'
|
||||
import iconsSvg from '../../../svg/icons'
|
||||
import { CONSTANTS } from '../../../constants/constant'
|
||||
|
||||
// 标签默认的样式
|
||||
const defaultTagStyle = {
|
||||
radius: 3, // 标签矩形的圆角大小
|
||||
fontSize: 12, // 字号,建议文字高度不要大于height
|
||||
fill: '', // 标签矩形的背景颜色
|
||||
height: 20, // 标签矩形的高度
|
||||
paddingX: 8 // 水平内边距,如果设置了width,将忽略该配置
|
||||
//width: 30 // 标签矩形的宽度,如果不设置,默认以文字的宽度+paddingX*2为宽度
|
||||
}
|
||||
|
||||
// 创建图片节点
|
||||
function createImgNode() {
|
||||
const img = this.getData('image')
|
||||
@@ -284,31 +295,69 @@ function createHyperlinkNode() {
|
||||
|
||||
// 创建标签节点
|
||||
function createTagNode() {
|
||||
let tagData = this.getData('tag')
|
||||
const tagData = this.getData('tag')
|
||||
if (!tagData || tagData.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let nodes = []
|
||||
tagData.slice(0, this.mindMap.opt.maxTag).forEach((item, index) => {
|
||||
let tag = new G()
|
||||
let { maxTag, tagsColorMap } = this.mindMap.opt
|
||||
tagsColorMap = tagsColorMap || {}
|
||||
const nodes = []
|
||||
tagData.slice(0, maxTag).forEach((item, index) => {
|
||||
let str = ''
|
||||
let style = {
|
||||
...defaultTagStyle
|
||||
}
|
||||
// 旧版只支持字符串类型
|
||||
if (typeof item === 'string') {
|
||||
str = item
|
||||
} else {
|
||||
// v0.10.3+版本支持对象类型
|
||||
str = item.text
|
||||
style = { ...defaultTagStyle, ...item.style }
|
||||
}
|
||||
// 是否手动设置了标签宽度
|
||||
const hasCustomWidth = typeof style.width !== 'undefined'
|
||||
// 创建容器节点
|
||||
const tag = new G()
|
||||
tag.on('click', () => {
|
||||
this.mindMap.emit('node_tag_click', this, item)
|
||||
this.mindMap.emit('node_tag_click', this, item, index, tag)
|
||||
})
|
||||
// 标签文本
|
||||
let text = new Text().text(item).x(8).cy(8)
|
||||
this.style.tagText(text, index)
|
||||
let { width } = text.bbox()
|
||||
const text = new Text().text(str)
|
||||
this.style.tagText(text, style)
|
||||
// 获取文本宽高
|
||||
const { width: textWidth, height: textHeight } = text.bbox()
|
||||
// 矩形宽度
|
||||
const rectWidth = hasCustomWidth
|
||||
? style.width
|
||||
: textWidth + style.paddingX * 2
|
||||
// 取文本和矩形最大宽高作为标签宽高
|
||||
const maxWidth = hasCustomWidth ? Math.max(rectWidth, textWidth) : rectWidth
|
||||
const maxHeight = Math.max(style.height, textHeight)
|
||||
// 文本居中
|
||||
if (hasCustomWidth) {
|
||||
text.x((maxWidth - textWidth) / 2)
|
||||
} else {
|
||||
text.x(hasCustomWidth ? 0 : style.paddingX)
|
||||
}
|
||||
text.cy(-maxHeight / 2)
|
||||
// 标签矩形
|
||||
let rect = new Rect().size(width + 16, 20)
|
||||
// 先从自定义的颜色中获取颜色,没有的话就按照内容生成
|
||||
const tagsColorList = this.mindMap.opt.tagsColorMap || {}
|
||||
const color = tagsColorList[text.node.textContent]
|
||||
this.style.tagRect(rect, text, color)
|
||||
const rect = new Rect().size(rectWidth, style.height).cy(-maxHeight / 2)
|
||||
if (hasCustomWidth) {
|
||||
rect.x((maxWidth - rectWidth) / 2)
|
||||
}
|
||||
this.style.tagRect(rect, {
|
||||
...style,
|
||||
fill:
|
||||
style.fill || // 优先节点自身配置
|
||||
tagsColorMap[text.node.textContent] || // 否则尝试从实例化选项tagsColorMap映射中获取颜色
|
||||
generateColorByContent(text.node.textContent) // 否则按照标签内容生成
|
||||
})
|
||||
tag.add(rect).add(text)
|
||||
nodes.push({
|
||||
node: tag,
|
||||
width: width + 16,
|
||||
height: 20
|
||||
width: maxWidth,
|
||||
height: maxHeight
|
||||
})
|
||||
})
|
||||
return nodes
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import btnsSvg from '../../../svg/btns'
|
||||
import { SVG, Circle, G } from '@svgdotjs/svg.js'
|
||||
import { SVG, Circle, G, Text } from '@svgdotjs/svg.js'
|
||||
|
||||
// 创建展开收起按钮的内容节点
|
||||
function createExpandNodeContent() {
|
||||
@@ -10,9 +10,7 @@ function createExpandNodeContent() {
|
||||
// 根据配置判断是否显示数量按钮
|
||||
if (this.mindMap.opt.isShowExpandNum) {
|
||||
// 展开的节点
|
||||
this._openExpandNode = SVG()
|
||||
.text()
|
||||
.size(this.expandBtnSize, this.expandBtnSize)
|
||||
this._openExpandNode = new Text()
|
||||
// 文本垂直居中
|
||||
this._openExpandNode.attr({
|
||||
'text-anchor': 'middle',
|
||||
@@ -81,7 +79,7 @@ function updateExpandBtnNode() {
|
||||
// 计算子节点数量
|
||||
let count = this.sumNode(this.nodeData.children)
|
||||
count = expandBtnNumHandler(count)
|
||||
node.text(count)
|
||||
node.text(String(count))
|
||||
} else {
|
||||
this._fillExpandNode.stroke('none')
|
||||
}
|
||||
@@ -126,11 +124,7 @@ function renderExpandBtn() {
|
||||
this._expandBtn.on('click', e => {
|
||||
e.stopPropagation()
|
||||
// 展开收缩
|
||||
this.mindMap.execCommand(
|
||||
'SET_NODE_EXPAND',
|
||||
this,
|
||||
!this.getData('expand')
|
||||
)
|
||||
this.mindMap.execCommand('SET_NODE_EXPAND', this, !this.getData('expand'))
|
||||
this.mindMap.emit('expand_btn_click', this)
|
||||
})
|
||||
this._expandBtn.on('dblclick', e => {
|
||||
|
||||
@@ -85,7 +85,7 @@ function updateGeneralization() {
|
||||
}
|
||||
|
||||
// 渲染概要节点
|
||||
function renderGeneralization() {
|
||||
function renderGeneralization(forceRender) {
|
||||
if (this.isGeneralization) return
|
||||
this.updateGeneralizationData()
|
||||
const list = this.formatGetGeneralization()
|
||||
@@ -100,7 +100,7 @@ function renderGeneralization() {
|
||||
this.renderer.layout.renderGeneralization(this._generalizationList)
|
||||
this._generalizationList.forEach(item => {
|
||||
this.style.generalizationLine(item.generalizationLine)
|
||||
item.generalizationNode.render()
|
||||
item.generalizationNode.render(() => {}, forceRender)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,11 @@ class Base {
|
||||
)
|
||||
newNode.reset()
|
||||
newNode.layerIndex = layerIndex
|
||||
if (isRoot) {
|
||||
newNode.isRoot = true
|
||||
} else {
|
||||
newNode.parent = parent._node
|
||||
}
|
||||
this.cacheNode(data._node.uid, newNode)
|
||||
this.checkIsLayoutChangeRerenderExpandBtnPlaceholderRect(newNode)
|
||||
// 主题或主题配置改变了、节点层级改变了,需要重新渲染节点文本等情况需要重新计算节点大小和布局
|
||||
@@ -112,6 +117,11 @@ class Base {
|
||||
newNode.reset()
|
||||
newNode.nodeData = newNode.handleData(data || {})
|
||||
newNode.layerIndex = layerIndex
|
||||
if (isRoot) {
|
||||
newNode.isRoot = true
|
||||
} else {
|
||||
newNode.parent = parent._node
|
||||
}
|
||||
this.cacheNode(uid, newNode)
|
||||
this.checkIsLayoutChangeRerenderExpandBtnPlaceholderRect(newNode)
|
||||
data._node = newNode
|
||||
@@ -137,7 +147,9 @@ class Base {
|
||||
renderer: this.renderer,
|
||||
mindMap: this.mindMap,
|
||||
draw: this.draw,
|
||||
layerIndex
|
||||
layerIndex,
|
||||
isRoot,
|
||||
parent: !isRoot ? parent._node : null
|
||||
})
|
||||
// uid保存到数据上,为了节点复用
|
||||
data.data.uid = newUid
|
||||
@@ -157,11 +169,9 @@ class Base {
|
||||
}
|
||||
// 根节点
|
||||
if (isRoot) {
|
||||
newNode.isRoot = true
|
||||
this.root = newNode
|
||||
} else {
|
||||
// 互相收集
|
||||
newNode.parent = parent._node
|
||||
parent._node.addChildren(newNode)
|
||||
}
|
||||
return newNode
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user