mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-20 15:38:27 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b4ca19ad8 | ||
|
|
eb72e0eed3 | ||
|
|
6dea1ef9b2 | ||
|
|
c6c1ef2117 | ||
|
|
4423fd562b | ||
|
|
7b1ea5e354 | ||
|
|
5192753816 | ||
|
|
6382e8acd8 | ||
|
|
e293039b3c | ||
|
|
f819cbc5b1 | ||
|
|
44a883c473 | ||
|
|
c1f600dc1f | ||
|
|
4777ab3e58 | ||
|
|
12c6479c0d | ||
|
|
f79918ec6f | ||
|
|
ba9a6e501a | ||
|
|
9b55d051dc | ||
|
|
159a4a202c | ||
|
|
ac72c0c1dc | ||
|
|
f54f92c303 | ||
|
|
c2dbfb41d5 | ||
|
|
5867649429 | ||
|
|
de29ec59c5 |
20
README.md
20
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,20 @@ 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>
|
||||
</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/夏虫不语冰.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
1
dist/js/chunk-2c6ccfd7.js
vendored
Normal file
1
dist/js/chunk-2c6ccfd7.js
vendored
Normal file
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-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
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-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-b84a6bba.js
vendored
Normal file
1
dist/js/chunk-b84a6bba.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?dca8675d85e0a079cc96" rel="stylesheet"><link href="dist/css/app.css?dca8675d85e0a079cc96" 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?dca8675d85e0a079cc96"></script><script src="dist/js/app.js?dca8675d85e0a079cc96"></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.3'
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.10.2",
|
||||
"version": "0.10.3",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
// 节点里图片和文字的间距
|
||||
@@ -379,6 +381,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 +395,9 @@ export const defaultOpt = {
|
||||
beforeHideRichTextEdit: null,
|
||||
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
|
||||
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果
|
||||
richTextEditFakeInPlace: false
|
||||
richTextEditFakeInPlace: false,
|
||||
|
||||
// 【OuterFrame】插件
|
||||
outerFramePaddingX: 10,
|
||||
outerFramePaddingY: 10
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ import {
|
||||
checkSmmFormatData,
|
||||
checkIsNodeStyleDataKey,
|
||||
removeRichTextStyes,
|
||||
formatGetNodeGeneralization
|
||||
formatGetNodeGeneralization,
|
||||
sortNodeList
|
||||
} from '../../utils'
|
||||
import { shapeList } from './node/Shape'
|
||||
import { lineStyleProps } from '../../themes/default'
|
||||
@@ -1373,7 +1374,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 +1387,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 +1668,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 +1688,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 +1720,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,18 +524,16 @@ 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
|
||||
}
|
||||
// 文字内容整体
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -31,11 +31,14 @@ class LogicalStructure extends Base {
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
computedBaseValue() {
|
||||
let sortIndex = 0
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
newNode.sortIndex = sortIndex
|
||||
sortIndex++
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
|
||||
@@ -2,7 +2,8 @@ import {
|
||||
bfsWalk,
|
||||
throttle,
|
||||
getTopAncestorsFomNodeList,
|
||||
getNodeIndexInNodeList
|
||||
getNodeIndexInNodeList,
|
||||
sortNodeList
|
||||
} from '../utils'
|
||||
import Base from '../layouts/Base'
|
||||
import { CONSTANTS } from '../constants/constant'
|
||||
@@ -258,11 +259,14 @@ class Drag extends Base {
|
||||
// 如果鼠标按下的节点是激活节点,那么保存当前所有激活的节点
|
||||
if (node.getData('isActive')) {
|
||||
// 找出这些激活节点中的最顶层节点
|
||||
this.beingDragNodeList = getTopAncestorsFomNodeList(
|
||||
// 过滤掉根节点和概要节点
|
||||
this.mindMap.renderer.activeNodeList.filter(item => {
|
||||
return !item.isRoot && !item.isGeneralization
|
||||
})
|
||||
// 并按索引从小到大排序
|
||||
this.beingDragNodeList = sortNodeList(
|
||||
getTopAncestorsFomNodeList(
|
||||
// 过滤掉根节点和概要节点
|
||||
this.mindMap.renderer.activeNodeList.filter(item => {
|
||||
return !item.isRoot && !item.isGeneralization
|
||||
})
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// 否则只拖拽按下的节点
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
readBlob,
|
||||
removeHTMLEntities,
|
||||
resizeImgSize,
|
||||
handleSelfCloseTags
|
||||
handleSelfCloseTags,
|
||||
addXmlns
|
||||
} from '../utils'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas'
|
||||
@@ -95,6 +96,20 @@ class Export {
|
||||
foreignObjectList[0].add(SVG(`<style>${resetCss}</style>`))
|
||||
svgIsChange = true
|
||||
}
|
||||
// 如果还开启了数学公式,还要插入katex库的样式
|
||||
if (this.mindMap.formula) {
|
||||
const formulaList = svg.find('.ql-formula')
|
||||
if (formulaList.length > 0) {
|
||||
const styleText = this.mindMap.formula.getStyleText()
|
||||
if (styleText) {
|
||||
const styleEl = document.createElement('style')
|
||||
styleEl.innerHTML = styleText
|
||||
addXmlns(styleEl)
|
||||
foreignObjectList[0].add(styleEl)
|
||||
svgIsChange = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 自定义处理svg的方法
|
||||
if (typeof handleBeingExportSvg === 'function') {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import katex from 'katex'
|
||||
import Quill from 'quill'
|
||||
import { getChromeVersion } from '../utils/index'
|
||||
import { getBaseStyleText, getFontStyleText } from './FormulaStyle'
|
||||
|
||||
// 数学公式支持插件
|
||||
// 该插件在富文本模式下可用
|
||||
@@ -11,6 +12,9 @@ class Formula {
|
||||
this.mindMap = opt.mindMap
|
||||
window.katex = katex
|
||||
this.init()
|
||||
this.config = this.getKatexConfig()
|
||||
this.cssEl = null
|
||||
this.addStyle()
|
||||
this.extendQuill()
|
||||
}
|
||||
|
||||
@@ -29,11 +33,18 @@ class Formula {
|
||||
errorColor: '#f00',
|
||||
output: 'mathml' // 默认只输出公式
|
||||
}
|
||||
// Chrome内核100以下,mathml配置公式无法正确渲染
|
||||
const chromeVersion = getChromeVersion()
|
||||
if (chromeVersion && chromeVersion <= 100) {
|
||||
config.output = 'html'
|
||||
}
|
||||
let { getKatexOutputType } = this.mindMap.opt
|
||||
getKatexOutputType =
|
||||
getKatexOutputType ||
|
||||
function () {
|
||||
// Chrome内核100以下,mathml配置公式无法正确渲染
|
||||
const chromeVersion = getChromeVersion()
|
||||
if (chromeVersion && chromeVersion <= 100) {
|
||||
return 'html'
|
||||
}
|
||||
}
|
||||
const output = getKatexOutputType() || 'mathml'
|
||||
config.output = ['mathml', 'html'].includes(output) ? output : 'mathml'
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -46,7 +57,7 @@ class Formula {
|
||||
static create(value) {
|
||||
let node = super.create(value)
|
||||
if (typeof value === 'string') {
|
||||
katex.render(value, node, self.getKatexConfig())
|
||||
katex.render(value, node, self.config)
|
||||
node.setAttribute('data-value', value)
|
||||
}
|
||||
return node
|
||||
@@ -56,6 +67,27 @@ class Formula {
|
||||
Quill.register('formats/formula', CustomFormulaBlot, true)
|
||||
}
|
||||
|
||||
getStyleText() {
|
||||
const { katexFontPath } = this.mindMap.opt
|
||||
let text = ''
|
||||
if (this.config.output === 'html') {
|
||||
text = getFontStyleText(katexFontPath)
|
||||
}
|
||||
text += getBaseStyleText()
|
||||
return text
|
||||
}
|
||||
|
||||
addStyle() {
|
||||
this.cssEl = document.createElement('style')
|
||||
this.cssEl.type = 'text/css'
|
||||
this.cssEl.innerHTML = this.getStyleText()
|
||||
document.head.appendChild(this.cssEl)
|
||||
}
|
||||
|
||||
removeStyle() {
|
||||
document.head.removeChild(this.cssEl)
|
||||
}
|
||||
|
||||
// 给指定的节点插入指定公式
|
||||
insertFormulaToNode(node, formula) {
|
||||
let richTextPlugin = this.mindMap.richText
|
||||
@@ -136,6 +168,16 @@ class Formula {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 插件被移除前做的事情
|
||||
beforePluginRemove() {
|
||||
this.removeStyle()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.removeStyle()
|
||||
}
|
||||
}
|
||||
|
||||
Formula.instanceName = 'formula'
|
||||
|
||||
1091
simple-mind-map/src/plugins/FormulaStyle.js
Normal file
1091
simple-mind-map/src/plugins/FormulaStyle.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -144,8 +144,6 @@ class OuterFrame {
|
||||
this.createDrawContainer()
|
||||
this.outerFrameElList = []
|
||||
this.activeOuterFrame = null
|
||||
this.paddingX = 10
|
||||
this.paddingY = 10
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
@@ -287,6 +285,7 @@ class OuterFrame {
|
||||
let tree = this.mindMap.renderer.root
|
||||
if (!tree) return
|
||||
const t = this.mindMap.draw.transform()
|
||||
const { outerFramePaddingX, outerFramePaddingY } = this.mindMap.opt
|
||||
walk(
|
||||
tree,
|
||||
null,
|
||||
@@ -299,12 +298,18 @@ class OuterFrame {
|
||||
const { left, top, width, height } =
|
||||
getNodeListBoundingRect(nodeList)
|
||||
const el = this.createOuterFrameEl(
|
||||
(left - this.paddingX - this.mindMap.elRect.left - t.translateX) /
|
||||
(left -
|
||||
outerFramePaddingX -
|
||||
this.mindMap.elRect.left -
|
||||
t.translateX) /
|
||||
t.scaleX,
|
||||
(top - this.paddingY - this.mindMap.elRect.top - t.translateY) /
|
||||
(top -
|
||||
outerFramePaddingY -
|
||||
this.mindMap.elRect.top -
|
||||
t.translateY) /
|
||||
t.scaleY,
|
||||
(width + this.paddingX * 2) / t.scaleX,
|
||||
(height + this.paddingY * 2) / t.scaleY,
|
||||
(width + outerFramePaddingX * 2) / t.scaleX,
|
||||
(height + outerFramePaddingY * 2) / t.scaleY,
|
||||
nodeList[0].getData('outerFrame') // 使用第一个节点的外框样式
|
||||
)
|
||||
el.on('click', e => {
|
||||
@@ -340,7 +345,7 @@ class OuterFrame {
|
||||
if (!this.activeOuterFrame) return
|
||||
const { el } = this.activeOuterFrame
|
||||
el.stroke({
|
||||
dasharray: '5,5'
|
||||
dasharray: el.cacheStyle.dasharray || defaultStyle.strokeDasharray
|
||||
})
|
||||
this.activeOuterFrame = null
|
||||
}
|
||||
@@ -362,6 +367,9 @@ class OuterFrame {
|
||||
})
|
||||
.x(x)
|
||||
.y(y)
|
||||
el.cacheStyle = {
|
||||
dasharray: styleConfig.strokeDasharray
|
||||
}
|
||||
this.outerFrameElList.push(el)
|
||||
return el
|
||||
}
|
||||
|
||||
@@ -1580,3 +1580,12 @@ export const defenseXSS = text => {
|
||||
export const addXmlns = el => {
|
||||
el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
|
||||
}
|
||||
|
||||
// 给一组节点实例升序排序,依据其sortIndex值
|
||||
export const sortNodeList = nodeList => {
|
||||
nodeList = [...nodeList]
|
||||
nodeList.sort((a, b) => {
|
||||
return a.sortIndex - b.sortIndex
|
||||
})
|
||||
return nodeList
|
||||
}
|
||||
|
||||
@@ -21,11 +21,15 @@
|
||||
src="//sdk.51.la/js-sdk-pro.min.js"
|
||||
></script>
|
||||
<script>
|
||||
LA.init({
|
||||
id: 'KRO0WxK8GT66tYCQ',
|
||||
ck: 'KRO0WxK8GT66tYCQ',
|
||||
autoTrack: false
|
||||
})
|
||||
try {
|
||||
LA.init({
|
||||
id: 'KRO0WxK8GT66tYCQ',
|
||||
ck: 'KRO0WxK8GT66tYCQ',
|
||||
autoTrack: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
BIN
web/src/assets/avatar/Tobin.jpg
Normal file
BIN
web/src/assets/avatar/Tobin.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
web/src/assets/avatar/夏虫不语冰.jpg
Normal file
BIN
web/src/assets/avatar/夏虫不语冰.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user