Compare commits

..

38 Commits

Author SHA1 Message Date
街角小林
9ef789110b 打包0.10.0 2024-06-05 09:29:59 +08:00
街角小林
9294fc4e7b Doc: update 2024-06-05 09:20:12 +08:00
街角小林
abacff6ede Doc:整理实例化选项文档 2024-06-04 18:53:43 +08:00
街角小林
79755e80b9 Fix:修复节点前后自定义内容导出图片时显示空白的问题 2024-06-04 16:30:23 +08:00
街角小林
b8a23beba4 Feat:打包后的文件中增加演示插件 2024-06-04 11:47:34 +08:00
街角小林
f996ec9bae Feat:支持直接在富文本编辑框中编辑数学公式 2024-06-04 11:45:31 +08:00
街角小林
8152fab185 Demo:新建和打开按钮增加导出的提示,防止内容丢失 2024-06-03 09:25:35 +08:00
wanglin2
21b404a322 Demo:优化富文本工具条下拉选项列表高度问题 2024-06-01 23:01:30 +08:00
街角小林
c5ed48ad99 Merge pull request #620 from wallace-yang/main
Feat:快捷键提示支持mac与修复富文本选择字体大小列表文字重叠bug
2024-06-01 22:49:41 +08:00
街角小林
25f0668a44 Feat:插入新节点时去除延时开启节点编辑的逻辑 2024-05-31 16:55:02 +08:00
街角小林
67fec82c72 update 2024-05-31 15:57:09 +08:00
街角小林
0760500ceb Feat:去除移除富文本内容中ql-cursor类名的节点的逻辑,修复文本换行时新增空行不生效的问题 2024-05-31 15:56:01 +08:00
街角小林
3355900bd3 Fix:修复复制带换行符的节点文本粘贴后会出现多行换行的问题 2024-05-31 15:08:31 +08:00
街角小林
417376dcb6 Feat:defenseXSS方法作为工具方法提供 2024-05-31 15:00:36 +08:00
街角小林
6a45ff2221 Feat:取消调用defenseXSS函数,对性能影响太大 2024-05-31 14:52:07 +08:00
街角小林
c967be2bc2 Fix:修复拖拽画布和拖拽调整图片时会选中文字的问题 2024-05-31 14:46:21 +08:00
街角小林
12dae210ef Merge branch 'feature' of https://github.com/wanglin2/mind-map into feature 2024-05-31 14:34:17 +08:00
街角小林
a75eb5f195 Feat:全新升级节点拖拽时的交互效果 2024-05-31 14:33:56 +08:00
wanglin2
9ad71c6627 update 2024-05-30 21:55:53 +08:00
wanglin2
2218e7bf12 Merge branch 'feature' of https://github.com/wanglin2/mind-map into feature 2024-05-30 21:49:11 +08:00
街角小林
c4777fb17a Doc: update 2024-05-29 17:47:28 +08:00
街角小林
edc2097d14 Doc: update 2024-05-29 17:45:58 +08:00
街角小林
53bcabe3d0 Fix:修复移动端部分浏览器设置缩放时会进行页面缩放的问题 2024-05-28 17:47:49 +08:00
街角小林
27477e39de Demo:导入存在多个画布的xmind文件支持选择指定的画布进行导入 2024-05-28 17:28:17 +08:00
街角小林
f4800746a3 Feat:导入存在多个画布的xmind文件支持选择指定的画布进行导入 2024-05-28 17:27:19 +08:00
街角小林
7c82d16d66 Demo:支持配置水印显示在节点下方 2024-05-27 19:14:00 +08:00
街角小林
dccd1c9459 Feat:支持设置水印显示在节点下方 2024-05-27 19:13:29 +08:00
街角小林
1f8fad8fc5 Feat:新增渲染开始事件node_tree_render_start 2024-05-27 18:41:50 +08:00
街角小林
a3d5588cd6 Doc: update 2024-05-27 18:39:04 +08:00
街角小林
7c96daf6d0 Fix:修复只读模式仍可通过Ctrl+点击节点方式激活节点 2024-05-27 18:31:42 +08:00
街角小林
db03e74f0d Doc: update 2024-05-27 18:24:44 +08:00
街角小林
459044beb9 Fix:修改51统计配置,解决报错的问题 2024-05-17 17:46:10 +08:00
街角小林
2537fb858f Merge branch 'main' of https://github.com/wanglin2/mind-map into main 2024-05-14 16:01:36 +08:00
街角小林
5c6d460455 打包demo 2024-05-14 16:01:05 +08:00
街角小林
6c3790e20e Delete CNAME 2024-05-14 14:57:25 +08:00
街角小林
40de891695 Create CNAME 2024-05-14 14:57:07 +08:00
yanghongbo1
bc9d118efd Fix:修复富文本选择字体大小列表文字重叠bug 2024-04-22 18:58:18 +08:00
yanghongbo1
950b7ad57b Feat:快捷键提示支持mac 2024-04-22 15:12:48 +08:00
83 changed files with 2800 additions and 1073 deletions

View File

@@ -109,9 +109,13 @@ const mindMap = new MindMap({
[![Star History Chart](https://api.star-history.com/svg?repos=wanglin2/mind-map&type=Date)](https://star-history.com/#wanglin2/mind-map&Date)
# 关于定制
如果你有个性化的商用定制需求,可以联系我们,我们提供付费开发服务。
# 请作者喝杯咖啡
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡,你的支持是开发者持续维护的最大动力~
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。
@@ -355,7 +359,7 @@ const mindMap = new MindMap({
</span>
<span>
<img src="./web/src/assets/avatar/孟照星.jpg" style="width: 50px;height: 50px;" />
<span>孟照星</span>
<span>Alex</span>
</span>
<span>
<img src="./web/src/assets/avatar/子豪.jpg" style="width: 50px;height: 50px;" />
@@ -365,4 +369,20 @@ const mindMap = new MindMap({
<img src="./web/src/assets/avatar/宏涛.jpg" style="width: 50px;height: 50px;" />
<span>宏涛</span>
</span>
<span>
<img src="./web/src/assets/avatar/最多5个字.jpg" style="width: 50px;height: 50px;" />
<span>最多5个字</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/ZX.jpg" style="width: 50px;height: 50px;" />
<span>ZX</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

File diff suppressed because one or more lines are too long

BIN
dist/img/ZX.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
dist/img/峰.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
dist/img/最多5个字.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
dist/img/雨馨.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

2
dist/js/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0ddf37"],{8427:function(v,_,s){"use strict";s.r(_);var n=function(){var v=this;v._self._c;return v._m(0)},e=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("XMind解析")]),_("blockquote",[_("p",[v._v("v0.2.7+")])]),_("p",[v._v("提供导入和导出"),_("code",[v._v("XMind")]),v._v("文件的方法。")]),_("h2",[v._v("引入")]),_("pre",{staticClass:"hljs"},[_("code",[_("span",{staticClass:"hljs-keyword"},[v._v("import")]),v._v(" xmind "),_("span",{staticClass:"hljs-keyword"},[v._v("from")]),v._v(" "),_("span",{staticClass:"hljs-string"},[v._v("'simple-mind-map/src/parse/xmind.js'")]),v._v("\n")])]),_("p",[v._v("如果使用的是"),_("code",[v._v("umd")]),v._v("格式的文件,那么可以通过如下方式获取:")]),_("pre",{staticClass:"hljs"},[_("code",[_("span",{staticClass:"hljs-tag"},[v._v("<"),_("span",{staticClass:"hljs-name"},[v._v("script")]),v._v(" "),_("span",{staticClass:"hljs-attr"},[v._v("src")]),v._v("="),_("span",{staticClass:"hljs-string"},[v._v('"simple-mind-map/dist/simpleMindMap.umd.min.js"')]),v._v(">")]),_("span",{staticClass:"hljs-tag"},[v._v("</"),_("span",{staticClass:"hljs-name"},[v._v("script")]),v._v(">")]),v._v("\n")])]),_("pre",{staticClass:"hljs"},[_("code",[v._v("simpleMindMap.xmind\n")])]),_("h2",[v._v("方法")]),_("h3",[v._v("xmind.parseXmindFile(file)")]),_("p",[v._v("解析"),_("code",[v._v(".xmind")]),v._v("文件,返回解析后的数据,可以使用"),_("code",[v._v("mindMap.setData(data)")]),v._v("来将返回的数据渲染到画布上")]),_("p",[_("code",[v._v("file")]),v._v(""),_("code",[v._v("File")]),v._v("对象")]),_("h3",[v._v("xmind.transformXmind(content)")]),_("blockquote",[_("p",[v._v("v0.6.6+版本该方法改为异步方法返回一个Promise实例")])]),_("p",[v._v("转换"),_("code",[v._v("xmind")]),v._v("数据,"),_("code",[v._v(".xmind")]),v._v("文件本质上是一个压缩包,改成"),_("code",[v._v("zip")]),v._v("后缀可以解压缩,里面存在一个"),_("code",[v._v("content.json")]),v._v("文件,如果你自己解析出了这个文件,那么可以把这个文件内容传递给这个方法进行转换,转换后的数据,可以使用"),_("code",[v._v("mindMap.setData(data)")]),v._v("来将返回的数据渲染到画布上")]),_("p",[_("code",[v._v("content")]),v._v(""),_("code",[v._v(".xmind")]),v._v("压缩包内的"),_("code",[v._v("content.json")]),v._v("文件内容")]),_("h3",[v._v("xmind.transformOldXmind(content)")]),_("blockquote",[_("p",[v._v("v0.2.8+")])]),_("p",[v._v("针对"),_("code",[v._v("xmind8")]),v._v("版本的数据解析,因为该版本的"),_("code",[v._v(".xmind")]),v._v("文件内没有"),_("code",[v._v("content.json")]),v._v(",对应的是"),_("code",[v._v("content.xml")]),v._v("。")]),_("p",[_("code",[v._v("content")]),v._v(""),_("code",[v._v(".xmind")]),v._v("压缩包内的"),_("code",[v._v("content.xml")]),v._v("文件内容")]),_("h3",[v._v("transformToXmind(data, name)")]),_("blockquote",[_("p",[v._v("v0.6.6+")])]),_("ul",[_("li",[_("p",[_("code",[v._v("data")]),v._v(""),_("code",[v._v("simple-mind-map")]),v._v("思维导图数据,可以通过"),_("code",[v._v("mindMap.getData()")]),v._v("方法获取。")])]),_("li",[_("p",[_("code",[v._v("name")]),v._v(":要导出的文件名。")])])]),_("p",[v._v("将"),_("code",[v._v("simple-mind-map")]),v._v("数据转为"),_("code",[v._v("xmind")]),v._v("文件。该方法为异步方法,返回一个"),_("code",[v._v("Promise")]),v._v("实例,返回的数据是一个"),_("code",[v._v("blob")]),v._v("类型的"),_("code",[v._v("zip")]),v._v("压缩包数据,你可以自行下载为文件。")])])}],t={},d=t,a=s("2877"),i=Object(a["a"])(d,n,e,!1,null,null,null);_["default"]=i.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0ddf37"],{8427:function(v,_,n){"use strict";n.r(_);var s=function(){var v=this;v._self._c;return v._m(0)},e=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("XMind解析")]),_("blockquote",[_("p",[v._v("v0.2.7+")])]),_("p",[v._v("提供导入和导出"),_("code",[v._v("XMind")]),v._v("文件的方法。")]),_("h2",[v._v("引入")]),_("pre",{staticClass:"hljs"},[_("code",[_("span",{staticClass:"hljs-keyword"},[v._v("import")]),v._v(" xmind "),_("span",{staticClass:"hljs-keyword"},[v._v("from")]),v._v(" "),_("span",{staticClass:"hljs-string"},[v._v("'simple-mind-map/src/parse/xmind.js'")]),v._v("\n")])]),_("p",[v._v("如果使用的是"),_("code",[v._v("umd")]),v._v("格式的文件,那么可以通过如下方式获取:")]),_("pre",{staticClass:"hljs"},[_("code",[_("span",{staticClass:"hljs-tag"},[v._v("<"),_("span",{staticClass:"hljs-name"},[v._v("script")]),v._v(" "),_("span",{staticClass:"hljs-attr"},[v._v("src")]),v._v("="),_("span",{staticClass:"hljs-string"},[v._v('"simple-mind-map/dist/simpleMindMap.umd.min.js"')]),v._v(">")]),_("span",{staticClass:"hljs-tag"},[v._v("</"),_("span",{staticClass:"hljs-name"},[v._v("script")]),v._v(">")]),v._v("\n")])]),_("pre",{staticClass:"hljs"},[_("code",[v._v("simpleMindMap.xmind\n")])]),_("h2",[v._v("方法")]),_("h3",[v._v("xmind.parseXmindFile(file, handleMultiCanvas)")]),_("p",[v._v("解析"),_("code",[v._v(".xmind")]),v._v("文件,返回解析后的数据,可以使用"),_("code",[v._v("mindMap.setData(data)")]),v._v("来将返回的数据渲染到画布上")]),_("p",[_("code",[v._v("file")]),v._v(""),_("code",[v._v("File")]),v._v("对象")]),_("p",[_("code",[v._v("handleMultiCanvas")]),v._v("v0.10.0+可选可传递一个函数如果导入的xmind文件存在多个画布那么会调用该函数函数接收xmind画布列表数据为参数需要返回其中一个画布的数据比如接收的参数为"),_("code",[v._v("content")]),v._v(",要导入第二个画布的数据则返回"),_("code",[v._v("content[1]")]),v._v("。函数可以是异步函数返回一个Promise实例。")]),_("h3",[v._v("xmind.transformXmind(content)")]),_("blockquote",[_("p",[v._v("v0.6.6+版本该方法改为异步方法返回一个Promise实例")])]),_("p",[v._v("转换"),_("code",[v._v("xmind")]),v._v("数据,"),_("code",[v._v(".xmind")]),v._v("文件本质上是一个压缩包,改成"),_("code",[v._v("zip")]),v._v("后缀可以解压缩,里面存在一个"),_("code",[v._v("content.json")]),v._v("文件,如果你自己解析出了这个文件,那么可以把这个文件内容传递给这个方法进行转换,转换后的数据,可以使用"),_("code",[v._v("mindMap.setData(data)")]),v._v("来将返回的数据渲染到画布上")]),_("p",[_("code",[v._v("content")]),v._v(""),_("code",[v._v(".xmind")]),v._v("压缩包内的"),_("code",[v._v("content.json")]),v._v("文件内容")]),_("h3",[v._v("xmind.transformOldXmind(content)")]),_("blockquote",[_("p",[v._v("v0.2.8+")])]),_("p",[v._v("针对"),_("code",[v._v("xmind8")]),v._v("版本的数据解析,因为该版本的"),_("code",[v._v(".xmind")]),v._v("文件内没有"),_("code",[v._v("content.json")]),v._v(",对应的是"),_("code",[v._v("content.xml")]),v._v("。")]),_("p",[_("code",[v._v("content")]),v._v(""),_("code",[v._v(".xmind")]),v._v("压缩包内的"),_("code",[v._v("content.xml")]),v._v("文件内容")]),_("h3",[v._v("transformToXmind(data, name)")]),_("blockquote",[_("p",[v._v("v0.6.6+")])]),_("ul",[_("li",[_("p",[_("code",[v._v("data")]),v._v(""),_("code",[v._v("simple-mind-map")]),v._v("思维导图数据,可以通过"),_("code",[v._v("mindMap.getData()")]),v._v("方法获取。")])]),_("li",[_("p",[_("code",[v._v("name")]),v._v(":要导出的文件名。")])])]),_("p",[v._v("将"),_("code",[v._v("simple-mind-map")]),v._v("数据转为"),_("code",[v._v("xmind")]),v._v("文件。该方法为异步方法,返回一个"),_("code",[v._v("Promise")]),v._v("实例,返回的数据是一个"),_("code",[v._v("blob")]),v._v("类型的"),_("code",[v._v("zip")]),v._v("压缩包数据,你可以自行下载为文件。")])])}],t={},d=t,a=n("2877"),i=Object(a["a"])(d,s,e,!1,null,null,null);_["default"]=i.exports}}]);

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-2d22a194.js vendored Normal file
View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22a194"],{dfea:function(p,v,_){"use strict";_.r(v);var e=function(){var p=this;p._self._c;return p._m(0)},t=[function(){var p=this,v=p._self._c;return v("div",[v("h1",[p._v("局域网docker部署解决HTTPS问题的一种方法")]),v("blockquote",[v("p",[p._v("本文来自:"),v("a",{attrs:{href:"https://github.com/Brzjomo"}},[p._v("Brzjomo")]),p._v("的"),v("a",{attrs:{href:"https://github.com/wanglin2/mind-map/issues/658"}},[p._v("issue")]),p._v("。")])]),v("p",[p._v("受Api的限制MindMap以HTTP访问时目录、新建和打开功能不能正常工作。因此在局域网架设时需要给它进行配置证书等操作使其正常工作。")]),v("p",[p._v("假设先前已经基于Github源码架设了MindMap的docker服务。没有的先看这个"),v("a",{attrs:{href:"https://github.com/wanglin2/mind-map/issues/309"}},[p._v("Issue")])]),v("p",[p._v("事前准备: 需要准备一个域名。")]),v("p",[p._v("需要安装Linux 服务器运维管理面板"),v("a",{attrs:{href:"https://github.com/1Panel-dev/1Panel"}},[p._v("1panel")])]),v("p",[p._v("设置域名解析: 以阿里云为例,登录后进入"),v("a",{attrs:{href:"https://dns.console.aliyun.com/#/dns/domainList"}},[p._v("域名解析页面")])]),v("p",[p._v("点击对应域名的解析设置。")]),v("p",[p._v("添加或编辑对应的@和www记录将IP记录值修改为局域网IP比如192.168.2.36。")]),v("p",[p._v("保存后退出。")]),v("p",[p._v("获取AccessKey 进入账号下面的AccessKey管理。")]),v("p",[p._v("创建或者使用已经记录的AccessKey。")]),v("p",[p._v("1panel设置 进入应用商店安装OpenResty稍后用于申请证书和设置反代。")]),v("p",[p._v("进入网站-网站,点击创建网站。")]),v("p",[p._v("点击反向代理。")]),v("p",[p._v("设置主域名为自己的域名。")]),v("p",[p._v("代理地址为http和127.0.0.1:MindMap容器端口。")]),v("p",[p._v("点击确认。")]),v("p",[p._v("创建证书申请账户: 进入1panel的网站-证书点击Acme 账户。")]),v("p",[p._v("点击创建账户。")]),v("p",[p._v("输入邮箱后确认。")]),v("p",[p._v("回到刚才的证书页面点击DNS 账户。")]),v("p",[p._v("点击创建账户。")]),v("p",[p._v("填写名称后选择类型为阿里云DNS。")]),v("p",[p._v("再填入刚才准备好的Access Key和Secret Key。")]),v("p",[p._v("点击确认。")]),v("p",[p._v("申请证书: 回到刚才的证书页面,点击申请证书。")]),v("p",[p._v("填写主域名,其他按实际情况填写。一般会自动设置。")]),v("p",[p._v("点击确认,等待其成功。")]),v("p",[p._v("启用HTTPS访问 回到1panel的网站管理页面。")]),v("p",[p._v("找到刚才建立的反向代理,点击配置。")]),v("p",[p._v("点击HTTPS。")]),v("p",[p._v("点击启用HTTPS。")]),v("p",[p._v("SSL 选项设置为选择已有证书。")]),v("p",[p._v("选择好刚才创建的Acme账户和证书。")]),v("p",[p._v("点击保存。")]),v("p",[p._v("此时在局域网内访问该域名应当能正确以Https访问MindMap了。")]),v("p",[p._v("如果不能输入host 域名查看返回的DNS解析是否为局域网IP。")])])}],s={},n=s,a=_("2877"),c=Object(a["a"])(n,e,t,!1,null,null,null);v["default"]=c.exports}}]);

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22bd06"],{f127:function(e,t,n){"use strict";n.r(t);var s=function(){var e=this;e._self._c;return e._m(0)},a=[function(){var e=this,t=e._self._c;return t("div",[t("h1",[e._v("XMind parse")]),t("blockquote",[t("p",[e._v("v0.2.7+")])]),t("p",[e._v("Provides methods for importing and export "),t("code",[e._v("XMind")]),e._v(" files.")]),t("h2",[e._v("Import")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[e._v("import")]),e._v(" xmind "),t("span",{staticClass:"hljs-keyword"},[e._v("from")]),e._v(" "),t("span",{staticClass:"hljs-string"},[e._v("'simple-mind-map/src/parse/xmind.js'")]),e._v("\n")])]),t("p",[e._v("If you are using the file in the format of "),t("code",[e._v("umd")]),e._v(", you can obtain it in the following way:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-tag"},[e._v("<"),t("span",{staticClass:"hljs-name"},[e._v("script")]),e._v(" "),t("span",{staticClass:"hljs-attr"},[e._v("src")]),e._v("="),t("span",{staticClass:"hljs-string"},[e._v('"simple-mind-map/dist/simpleMindMap.umd.min.js"')]),e._v(">")]),t("span",{staticClass:"hljs-tag"},[e._v("</"),t("span",{staticClass:"hljs-name"},[e._v("script")]),e._v(">")]),e._v("\n")])]),t("pre",{staticClass:"hljs"},[t("code",[e._v("simpleMindMap.xmind\n")])]),t("h2",[e._v("Methods")]),t("h3",[e._v("xmind.parseXmindFile(file)")]),t("p",[e._v("Parsing the "),t("code",[e._v(".xmind")]),e._v(" file and returning the parsed data. You can use "),t("code",[e._v("mindMap.setData(data)")]),e._v(" to render the returned data to the canvas.")]),t("p",[t("code",[e._v("file")]),e._v(": "),t("code",[e._v("File")]),e._v(" object")]),t("h3",[e._v("xmind.transformXmind(content)")]),t("blockquote",[t("p",[e._v("V0.6.6+version changes the method to asynchronous and returns a Promise instance")])]),t("p",[e._v("Convert "),t("code",[e._v("xmind")]),e._v(" data. The "),t("code",[e._v(".xmind")]),e._v(" file is essentially a "),t("code",[e._v("zip")]),e._v(" file that can be decompressed by changing the suffix to zip. Inside, there is a "),t("code",[e._v("content.json")]),e._v(" file. If you have parsed this file yourself, you can pass the contents of this file to this method for conversion. You can use "),t("code",[e._v("mindMap.setData(data)")]),e._v(" to render the returned data to the canvas.")]),t("p",[t("code",[e._v("content")]),e._v(": the contents of the "),t("code",[e._v("content.json")]),e._v(" file within the "),t("code",[e._v(".xmind")]),e._v(" zip package")]),t("h3",[e._v("xmind.transformOldXmind(content)")]),t("blockquote",[t("p",[e._v("v0.2.8+")])]),t("p",[e._v("For data parsing of the "),t("code",[e._v("xmind8")]),e._v(" version, because the "),t("code",[e._v(".xmind")]),e._v(" file in this version does not have a "),t("code",[e._v("content.json")]),e._v(", it corresponds to "),t("code",[e._v("content.xml")]),e._v(".")]),t("p",[t("code",[e._v("content")]),e._v(": the contents of the "),t("code",[e._v("content.xml")]),e._v(" file within the "),t("code",[e._v(".xmind")]),e._v(" zip package")]),t("h3",[e._v("transformToXmind(data, name)")]),t("blockquote",[t("p",[e._v("v0.6.6+")])]),t("ul",[t("li",[t("p",[t("code",[e._v("data")]),e._v(": "),t("code",[e._v("simple-mind-map")]),e._v(" data, you can get it by "),t("code",[e._v("mindMap.getData()")]),e._v(" method.")])]),t("li",[t("p",[t("code",[e._v("name")]),e._v(": The file name to export.")])])]),t("p",[e._v("Convert the "),t("code",[e._v("simple mind map")]),e._v(" data to an "),t("code",[e._v("xmind")]),e._v(" file. This method is asynchronous and returns an instance of "),t("code",[e._v("Promise")]),e._v(". The returned data is a "),t("code",[e._v("blob")]),e._v(" type "),t("code",[e._v("zip")]),e._v(" compressed package data, which you can download as a file yourself.")])])}],o={},i=o,d=n("2877"),v=Object(d["a"])(i,s,a,!1,null,null,null);t["default"]=v.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22bd06"],{f127:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this;e._self._c;return e._m(0)},s=[function(){var e=this,t=e._self._c;return t("div",[t("h1",[e._v("XMind parse")]),t("blockquote",[t("p",[e._v("v0.2.7+")])]),t("p",[e._v("Provides methods for importing and export "),t("code",[e._v("XMind")]),e._v(" files.")]),t("h2",[e._v("Import")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[e._v("import")]),e._v(" xmind "),t("span",{staticClass:"hljs-keyword"},[e._v("from")]),e._v(" "),t("span",{staticClass:"hljs-string"},[e._v("'simple-mind-map/src/parse/xmind.js'")]),e._v("\n")])]),t("p",[e._v("If you are using the file in the format of "),t("code",[e._v("umd")]),e._v(", you can obtain it in the following way:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-tag"},[e._v("<"),t("span",{staticClass:"hljs-name"},[e._v("script")]),e._v(" "),t("span",{staticClass:"hljs-attr"},[e._v("src")]),e._v("="),t("span",{staticClass:"hljs-string"},[e._v('"simple-mind-map/dist/simpleMindMap.umd.min.js"')]),e._v(">")]),t("span",{staticClass:"hljs-tag"},[e._v("</"),t("span",{staticClass:"hljs-name"},[e._v("script")]),e._v(">")]),e._v("\n")])]),t("pre",{staticClass:"hljs"},[t("code",[e._v("simpleMindMap.xmind\n")])]),t("h2",[e._v("Methods")]),t("h3",[e._v("xmind.parseXmindFile(file, handleMultiCanvas)")]),t("p",[e._v("Parsing the "),t("code",[e._v(".xmind")]),e._v(" file and returning the parsed data. You can use "),t("code",[e._v("mindMap.setData(data)")]),e._v(" to render the returned data to the canvas.")]),t("p",[t("code",[e._v("file")]),e._v(": "),t("code",[e._v("File")]),e._v(" object")]),t("p",[t("code",[e._v("handleMultiCanvas")]),e._v("v0.10.0+Optional, a function can be passed. If there are multiple canvases in the imported xmind file, this function will be called. The function takes the xmind canvas list data as a parameter and needs to return the data of one of the canvases, For example, if the received parameter is 'content', if you want to import data from the second canvas, you will return 'content[1]'. A function can be an asynchronous function that returns a Promise instance.")]),t("h3",[e._v("xmind.transformXmind(content)")]),t("blockquote",[t("p",[e._v("V0.6.6+version changes the method to asynchronous and returns a Promise instance")])]),t("p",[e._v("Convert "),t("code",[e._v("xmind")]),e._v(" data. The "),t("code",[e._v(".xmind")]),e._v(" file is essentially a "),t("code",[e._v("zip")]),e._v(" file that can be decompressed by changing the suffix to zip. Inside, there is a "),t("code",[e._v("content.json")]),e._v(" file. If you have parsed this file yourself, you can pass the contents of this file to this method for conversion. You can use "),t("code",[e._v("mindMap.setData(data)")]),e._v(" to render the returned data to the canvas.")]),t("p",[t("code",[e._v("content")]),e._v(": the contents of the "),t("code",[e._v("content.json")]),e._v(" file within the "),t("code",[e._v(".xmind")]),e._v(" zip package")]),t("h3",[e._v("xmind.transformOldXmind(content)")]),t("blockquote",[t("p",[e._v("v0.2.8+")])]),t("p",[e._v("For data parsing of the "),t("code",[e._v("xmind8")]),e._v(" version, because the "),t("code",[e._v(".xmind")]),e._v(" file in this version does not have a "),t("code",[e._v("content.json")]),e._v(", it corresponds to "),t("code",[e._v("content.xml")]),e._v(".")]),t("p",[t("code",[e._v("content")]),e._v(": the contents of the "),t("code",[e._v("content.xml")]),e._v(" file within the "),t("code",[e._v(".xmind")]),e._v(" zip package")]),t("h3",[e._v("transformToXmind(data, name)")]),t("blockquote",[t("p",[e._v("v0.6.6+")])]),t("ul",[t("li",[t("p",[t("code",[e._v("data")]),e._v(": "),t("code",[e._v("simple-mind-map")]),e._v(" data, you can get it by "),t("code",[e._v("mindMap.getData()")]),e._v(" method.")])]),t("li",[t("p",[t("code",[e._v("name")]),e._v(": The file name to export.")])])]),t("p",[e._v("Convert the "),t("code",[e._v("simple mind map")]),e._v(" data to an "),t("code",[e._v("xmind")]),e._v(" file. This method is asynchronous and returns an instance of "),t("code",[e._v("Promise")]),e._v(". The returned data is a "),t("code",[e._v("blob")]),e._v(" type "),t("code",[e._v("zip")]),e._v(" compressed package data, which you can download as a file yourself.")])])}],o={},i=o,d=n("2877"),v=Object(d["a"])(i,a,s,!1,null,null,null);t["default"]=v.exports}}]);

1
dist/js/chunk-2d22dd95.js vendored Normal file
View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22dd95"],{f8f3:function(n,t,u){"use strict";u.r(t);var _=function(){var n=this;n._self._c;return n._m(0)},c=[function(){var n=this,t=n._self._c;return t("div",[t("h1",[n._v("如何编辑数学公式")]),t("p",[n._v("数学公式只在开启了【富文本】编辑模式下才可使用。")]),t("p",[n._v("首先可以激活节点,然后点击上方工具栏中的【公式】打开右侧的格式侧边栏,然后再输入框中输入公式后点击【完成】即可将公式输入节点。")]),t("p",[n._v("当你再次双击节点时,公式会转换成源码,你可以直接修改,回车完成后即可渲染。")]),t("p",[n._v("所以你也可以不通过侧边栏,直接在文本编辑框中输入公式,不过公式的源码前后必须通过"),t("code",[n._v("$")]),n._v("符号包裹,否则不会解析为格式。")])])}],e={},v=e,p=u("2877"),r=Object(p["a"])(v,_,c,!1,null,null,null);t["default"]=r.exports}}]);

1
dist/js/chunk-337a3983.js vendored Normal file

File diff suppressed because one or more lines are too long

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-bb91a162.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,24 +1,28 @@
<!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><link href="dist/css/chunk-vendors.css?78d97b280dca5d10b8bc" rel="stylesheet"><link href="dist/css/app.css?78d97b280dca5d10b8bc" 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>LA.init({
id: 'KRO0WxK8GT66tYCQ',
ck: 'KRO0WxK8GT66tYCQ',
autoTrack: false
})</script><link href="dist/css/chunk-vendors.css?b34a2f0278e7d1ccab6a" rel="stylesheet"><link href="dist/css/app.css?b34a2f0278e7d1ccab6a" 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({
mindMapData: {
root:{
"data": {
"text": "根节点"
root: {
data: {
text: '根节点'
},
"children": []
children: []
},
theme:{
"template":"avocado",
"config":{}
theme: {
template: 'avocado',
config: {}
},
layout:"logicalStructure",
layout: 'logicalStructure',
config: {},
view: null,
view: null
},
lang: 'zh',
localConfig: null
@@ -26,14 +30,14 @@
}, 200)
})
}
const setTakeOverAppMethods = (data) => {
const setTakeOverAppMethods = data => {
window.takeOverAppMethods = {}
// 获取思维导图数据的函数
window.takeOverAppMethods.getMindMapData = () => {
return data.mindMapData
}
}
// 保存思维导图数据的函数
window.takeOverAppMethods.saveMindMapData = (data) => {
window.takeOverAppMethods.saveMindMapData = data => {
console.log(data)
}
// 获取语言的函数
@@ -41,7 +45,7 @@
return data.lang
}
// 保存语言的函数
window.takeOverAppMethods.saveLanguage = (lang) => {
window.takeOverAppMethods.saveLanguage = lang => {
console.log(lang)
}
// 获取本地配置的函数
@@ -49,7 +53,7 @@
return data.localConfig
}
// 保存本地配置的函数
window.takeOverAppMethods.saveLocalConfig = (config) => {
window.takeOverAppMethods.saveLocalConfig = config => {
console.log(config)
}
}
@@ -60,10 +64,10 @@
// 设置全局的方法
setTakeOverAppMethods(data)
// 思维导图实例创建完成事件
window.$bus.$on('app_inited', (mindMap) => {
window.$bus.$on('app_inited', mindMap => {
console.log(mindMap)
})
// 可以通过window.$bus.$on()来监听应用的一些事件
// 实例化页面
window.initApp()
}</script><script src="dist/js/chunk-vendors.js?78d97b280dca5d10b8bc"></script><script src="dist/js/app.js?78d97b280dca5d10b8bc"></script></body></html>
}</script><script src="dist/js/chunk-vendors.js?b34a2f0278e7d1ccab6a"></script><script src="dist/js/app.js?b34a2f0278e7d1ccab6a"></script></body></html>

View File

@@ -16,6 +16,7 @@ import Painter from './src/plugins/Painter.js'
import Scrollbar from './src/plugins/Scrollbar.js'
import Formula from './src/plugins/Formula.js'
import RainbowLines from './src/plugins/RainbowLines.js'
import Demonstrate from './src/plugins/Demonstrate.js'
import xmind from './src/parse/xmind.js'
import markdown from './src/parse/markdown.js'
import icons from './src/svg/icons.js'
@@ -29,7 +30,7 @@ MindMap.iconList = icons.nodeIconList
MindMap.constants = constants
MindMap.themes = themes
MindMap.defaultTheme = defaultTheme
MindMap.version = '0.9.12'
MindMap.version = '0.10.0'
MindMap.usePlugin(MiniMap)
.usePlugin(Watermark)
@@ -48,5 +49,6 @@ MindMap.usePlugin(MiniMap)
.usePlugin(Scrollbar)
.usePlugin(Formula)
.usePlugin(RainbowLines)
.usePlugin(Demonstrate)
export default MindMap

View File

@@ -136,10 +136,8 @@ class MindMap {
this.associativeLineDraw.addClass('smm-associative-line-container')
}
// 画布
this.svg = SVG()
.addTo(this.el)
.size(this.width, this.height)
this.svg = SVG().addTo(this.el).size(this.width, this.height)
// 容器
this.draw = this.svg.group()
this.draw.addClass('smm-container')

View File

@@ -1,6 +1,6 @@
{
"name": "simple-mind-map",
"version": "0.9.12",
"version": "0.10.0",
"description": "一个简单的web在线思维导图",
"authors": [
{

View File

@@ -2,6 +2,11 @@ import { CONSTANTS } from './constant'
// 默认选项配置
export const defaultOpt = {
// 【基本】
// 容器元素必传必须为DOM元素
el: null,
// 思维导图回显数据
data: null,
// 是否只读
readonly: false,
// 布局
@@ -24,10 +29,6 @@ export const defaultOpt = {
imgTextMargin: 5,
// 节点里各种文字信息的间距,如图标和文字的间距
textContentMargin: 2,
// 多选节点时鼠标移动到边缘时的画布移动偏移量
selectTranslateStep: 3,
// 多选节点时鼠标移动距边缘多少距离时开始偏移
selectTranslateLimit: 20,
// 自定义节点备注内容显示
customNoteContentShow: null,
/*
@@ -36,21 +37,6 @@ export const defaultOpt = {
hide(){}
}
*/
// 是否开启节点自由拖拽
enableFreeDrag: false,
// 水印配置
watermarkConfig: {
onlyExport: false, // 是否仅在导出时添加水印
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '#999',
opacity: 0.5,
fontSize: 14
}
},
// 达到该宽度文本自动换行
textAutoWrapWidth: 500,
// 自定义鼠标滚轮事件处理
@@ -88,9 +74,6 @@ export const defaultOpt = {
enableShortcutOnlyWhenMouseInSvg: true,
// 初始根节点的位置
initRootNodePosition: null,
// 导出png、svg、pdf时的图形内边距注意是单侧内边距
exportPaddingX: 10,
exportPaddingY: 10,
// 节点文本编辑框的z-index
nodeTextEditZIndex: 3000,
// 节点备注浮层的z-index
@@ -116,8 +99,6 @@ export const defaultOpt = {
],
// 节点最大缓存数量
maxNodeCacheCount: 1000,
// 关联线默认文字
defaultAssociativeLineText: '关联',
// 思维导图适应画布大小时的内边距
fitPadding: 50,
// 是否开启按住ctrl键多选节点功能
@@ -132,14 +113,9 @@ export const defaultOpt = {
customCreateNodeContent: null,
// 指定内部一些元素节点文本编辑元素、节点备注显示元素、关联线文本编辑元素、节点图片调整按钮元素添加到的位置默认添加到document.body下
customInnerElsAppendTo: null,
// 拖拽元素时,指示元素新位置的块的最大高度
nodeDragPlaceholderMaxSize: 20,
// 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式
// 开启该特性后需要给你的输入框绑定keydown事件并禁止冒泡
enableAutoEnterTextEditWhenKeydown: false,
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果
richTextEditFakeInPlace: false,
// 自定义对剪贴板文本的处理。当按ctrl+v粘贴时会读取用户剪贴板中的文本和图片默认只会判断文本是否是普通文本和simple-mind-map格式的节点数据如果你想处理其他思维导图的数据比如processon、zhixi等那么可以传递一个函数接受当前剪贴板中的文本为参数返回处理后的数据可以返回两种类型
/*
1.返回一个纯文本,那么会直接以该文本创建一个子节点
@@ -161,26 +137,12 @@ export const defaultOpt = {
customHandleClipboardText: null,
// 禁止鼠标滚轮缩放你仍旧可以使用api进行缩放
disableMouseWheelZoom: false,
// 禁止双指缩放你仍旧可以使用api进行缩放
// 需要注册TouchEvent插件后生效
disableTouchZoom: false,
// 错误处理函数
errorHandler: (code, error) => {
console.error(code, error)
},
// 设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖
// 如果不覆盖,会发生偏移问题
resetCss: `
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
`,
// 是否在鼠标双击时回到根节点,也就是让根节点居中显示
enableDblclickBackToRootNode: false,
// 导出图片时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值
minExportImgCanvasScale: 2,
// 节点鼠标hover和激活时显示的矩形边框的颜色
hoverRectColor: 'rgb(94, 200, 248)',
// 节点鼠标hover和激活时显示的矩形边框距节点内容的距离
@@ -189,23 +151,8 @@ export const defaultOpt = {
selectTextOnEnterEditText: false,
// 删除节点后激活相邻节点
deleteNodeActive: true,
// 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动
autoMoveWhenMouseInEdgeOnDrag: true,
// 是否首次加载fit view
fit: false,
// 拖拽多个节点时随鼠标移动的示意矩形的样式配置
dragMultiNodeRectConfig: {
width: 40,
height: 20,
fill: '' // 填充颜色,如果不传默认使用连线的颜色
},
// 节点拖拽时新位置的示意矩形的填充颜色,如果不传默认使用连线的颜色
dragPlaceholderRectFill: '',
// 节点拖拽时的透明度配置
dragOpacityConfig: {
cloneNodeOpacity: 0.5, // 跟随鼠标移动的克隆节点或矩形的透明度
beingDragNodeOpacity: 0.3 // 被拖拽节点的透明度
},
// 自定义标签的颜色
// {pass: 'green, unpass: 'red'}
tagsColorMap: {},
@@ -214,9 +161,8 @@ export const defaultOpt = {
avatarSize: 22, // 头像大小
fontSize: 12 // 如果是文字头像,那么文字的大小
},
// 关联线是否始终显示在节点上层
// false即创建关联线和激活关联线时处于最顶层其他情况下处于节点下方
associativeLineIsAlwaysAboveNode: true,
// 协同编辑时,同一个节点不能同时被多人选中
onlyOneEnableActiveNodeOnCooperate: false,
// 插入概要的默认文本
defaultGeneralizationText: '概要',
// 粘贴文本的方式创建新节点时,控制是否按换行自动分割节点,即如果存在换行,那么会根据换行创建多个节点,否则只会创建一个节点
@@ -243,8 +189,6 @@ export const defaultOpt = {
// 是否将思维导图限制在画布内
// 比如向右拖动时,思维导图图形的最左侧到达画布中心时将无法继续向右拖动,其他同理
isLimitMindMapInCanvas: false,
// 当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas不再起作用
isLimitMindMapInCanvasWhenHasScrollbar: true,
// 在节点上粘贴剪贴板中的图片的处理方法默认是转换为data:url数据插入到节点中你可以通过该方法来将图片数据上传到服务器实现保存图片的url
// 可以传递一个异步方法接收Blob类型的图片数据需要返回如下结构
/*
@@ -257,15 +201,6 @@ export const defaultOpt = {
}
*/
handleNodePasteImg: null,
// 默认情况下,新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的,如果你想固定位置,可以通过这个属性来配置
// from和to都不传则都自动计算如果只传一个另一个则会自动计算
associativeLineInitPointsPosition: {
// from和to可选值left、top、bottom、right
from: '', // 关联线起始节点上端点的位置
to: '' // 关联线目标节点上端点的位置
},
// 是否允许调整关联线两个端点的位置
enableAdjustAssociativeLinePoints: true,
// 自定义创建节点形状的方法,可以传一个函数,均接收一个参数
// 矩形、圆角矩形、椭圆、圆等形状会调用该方法
// 接收svg path字符串返回svg节点
@@ -276,10 +211,119 @@ export const defaultOpt = {
// 自定义转换节点连线路径的方法
// 接收svg path字符串返回转换后的svg path字符串
customTransformNodeLinePath: null,
// 快捷键操作即将执行前的生命周期函数返回true可以阻止操作执行
// 函数接收两个参数key快捷键、activeNodeList当前激活的节点列表
beforeShortcutRun: null,
// 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%
resetScaleOnMoveNodeToCenter: false,
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
createNodePrefixContent: null,
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
createNodePostfixContent: null,
// 【Select插件】
// 多选节点时鼠标移动到边缘时的画布移动偏移量
selectTranslateStep: 3,
// 多选节点时鼠标移动距边缘多少距离时开始偏移
selectTranslateLimit: 20,
// 【Drag插件】
// 是否开启节点自由拖拽
enableFreeDrag: false,
// 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动
autoMoveWhenMouseInEdgeOnDrag: true,
// 拖拽多个节点时随鼠标移动的示意矩形的样式配置
dragMultiNodeRectConfig: {
width: 40,
height: 20,
fill: 'rgb(94, 200, 248)' // 填充颜色
},
// 节点拖拽时新位置的示意矩形的填充颜色
dragPlaceholderRectFill: 'rgb(94, 200, 248)',
// 节点拖拽时新位置的示意连线的样式配置
dragPlaceholderLineConfig: {
color: 'rgb(94, 200, 248)',
width: 2
},
// 节点拖拽时的透明度配置
dragOpacityConfig: {
cloneNodeOpacity: 0.5, // 跟随鼠标移动的克隆节点或矩形的透明度
beingDragNodeOpacity: 0.3 // 被拖拽节点的透明度
},
// 【Watermark插件】
// 水印配置
watermarkConfig: {
onlyExport: false, // 是否仅在导出时添加水印
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '#999',
opacity: 0.5,
fontSize: 14
},
belowNode: false
},
// 【Export插件】
// 导出png、svg、pdf时的图形内边距注意是单侧内边距
exportPaddingX: 10,
exportPaddingY: 10,
// 设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖
// 如果不覆盖,会发生偏移问题
resetCss: `
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
`,
// 导出图片时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值
minExportImgCanvasScale: 2,
// 导出png、svg、pdf时在头部和尾部添加自定义内容
// 可传递一个函数这个函数可以返回null代表不添加内容也可以返回如下数据
/*
{
el,// 要追加的自定义DOM节点样式可内联
cssText,// 可选如果样式不想内联可以传递该值一个css字符串
height: 50// 返回的DOM节点的高度必须传递
}
*/
addContentToHeader: null,
addContentToFooter: null,
// 【AssociativeLine插件】
// 关联线默认文字
defaultAssociativeLineText: '关联',
// 关联线是否始终显示在节点上层
// false即创建关联线和激活关联线时处于最顶层其他情况下处于节点下方
associativeLineIsAlwaysAboveNode: true,
// 默认情况下,新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的,如果你想固定位置,可以通过这个属性来配置
// from和to都不传则都自动计算如果只传一个另一个则会自动计算
associativeLineInitPointsPosition: {
// from和to可选值left、top、bottom、right
from: '', // 关联线起始节点上端点的位置
to: '' // 关联线目标节点上端点的位置
},
// 是否允许调整关联线两个端点的位置
enableAdjustAssociativeLinePoints: true,
// 【TouchEvent插件】
// 禁止双指缩放你仍旧可以使用api进行缩放
// 需要注册TouchEvent插件后生效
disableTouchZoom: false,
// 【Scrollbar插件】
// 当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas不再起作用
isLimitMindMapInCanvasWhenHasScrollbar: true,
// 【Search插件】
// 是否仅搜索当前渲染的节点,被收起的节点不会被搜索到
isOnlySearchCurrentRenderNodes: false,
// 协同编辑时,同一个节点不能同时被多人选中
onlyOneEnableActiveNodeOnCooperate: false,
// 【Cooperate插件】
// 协同编辑时,节点操作即将更新到其他客户端前的生命周期函数
// 函数接收一个对象作为参数:
/*
@@ -289,9 +333,8 @@ export const defaultOpt = {
}
*/
beforeCooperateUpdate: null,
// 快捷键操作即将执行前的生命周期函数返回true可以阻止操作执行
// 函数接收两个参数key快捷键、activeNodeList当前激活的节点列表
beforeShortcutRun: null,
// 【RainbowLines插件】
// 彩虹线条配置需要先注册RainbowLines插件
rainbowLinesConfig: {
open: false, // 是否开启彩虹线条
@@ -308,23 +351,21 @@ export const defaultOpt = {
]
*/
},
// 导出png、svg、pdf时在头部和尾部添加自定义内容
// 可传递一个函数这个函数可以返回null代表不添加内容也可以返回如下数据
/*
{
el,// 要追加的自定义DOM节点样式可内联
cssText,// 可选如果样式不想内联可以传递该值一个css字符串
height: 50// 返回的DOM节点的高度必须传递
}
*/
addContentToHeader: null,
addContentToFooter: null,
// 【Demonstrate插件】
// 演示插件配置
demonstrateConfig: null,
// 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%
resetScaleOnMoveNodeToCenter: false,
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
createNodePrefixContent: null,
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
createNodePostfixContent: null
// 【Formula插件】
// 是否开启在富文本编辑框中直接编辑数学公式
enableEditFormulaInRichTextEdit: true,
// 【RichText插件】
// 转换富文本内容,当进入富文本编辑时,可以通过该参数传递一个函数,函数接收文本内容,需要返回你处理后的文本内容
transformRichTextOnEnterEdit: null,
// 可以传递一个函数即将结束富文本编辑前会执行该函数函数接收richText实例所以你可以在此时机更新quill文档数据
beforeHideRichTextEdit: null,
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果
richTextEditFakeInPlace: false,
}

View File

@@ -448,6 +448,7 @@ class Render {
this.mindMap.emit('node_tree_render_end')
return
}
this.mindMap.emit('node_tree_render_start')
// 计算布局
this.layout.doLayout(root => {
// 删除本次渲染时不再需要的节点

View File

@@ -8,12 +8,18 @@ import nodeCreateContentsMethods from './nodeCreateContents'
import nodeExpandBtnPlaceholderRectMethods from './nodeExpandBtnPlaceholderRect'
import nodeCooperateMethods from './nodeCooperate'
import { CONSTANTS } from '../../../constants/constant'
import { copyNodeTree, createForeignObjectNode } from '../../../utils/index'
import {
copyNodeTree,
createForeignObjectNode,
createUid,
addXmlns
} from '../../../utils/index'
// 节点类
class Node {
// 构造函数
constructor(opt = {}) {
this.opt = opt
// 节点数据
this.nodeData = this.handleData(opt.data || {})
// uid
@@ -111,31 +117,35 @@ class Node {
this.needLayout = false
// 当前是否是隐藏状态
this.isHide = false
// 概要相关方法
Object.keys(nodeGeneralizationMethods).forEach(item => {
this[item] = nodeGeneralizationMethods[item].bind(this)
})
// 展开收起按钮相关方法
Object.keys(nodeExpandBtnMethods).forEach(item => {
this[item] = nodeExpandBtnMethods[item].bind(this)
})
// 展开收起按钮占位元素相关方法
Object.keys(nodeExpandBtnPlaceholderRectMethods).forEach(item => {
this[item] = nodeExpandBtnPlaceholderRectMethods[item].bind(this)
})
// 命令的相关方法
Object.keys(nodeCommandWrapsMethods).forEach(item => {
this[item] = nodeCommandWrapsMethods[item].bind(this)
})
// 创建节点内容的相关方法
Object.keys(nodeCreateContentsMethods).forEach(item => {
this[item] = nodeCreateContentsMethods[item].bind(this)
})
// 协同相关
if (this.mindMap.cooperate) {
Object.keys(nodeCooperateMethods).forEach(item => {
this[item] = nodeCooperateMethods[item].bind(this)
const proto = Object.getPrototypeOf(this)
if (!proto.bindEvent) {
// 概要相关方法
Object.keys(nodeGeneralizationMethods).forEach(item => {
proto[item] = nodeGeneralizationMethods[item]
})
// 展开收起按钮相关方法
Object.keys(nodeExpandBtnMethods).forEach(item => {
proto[item] = nodeExpandBtnMethods[item]
})
// 展开收起按钮占位元素相关方法
Object.keys(nodeExpandBtnPlaceholderRectMethods).forEach(item => {
proto[item] = nodeExpandBtnPlaceholderRectMethods[item]
})
// 命令的相关方法
Object.keys(nodeCommandWrapsMethods).forEach(item => {
proto[item] = nodeCommandWrapsMethods[item]
})
// 创建节点内容的相关方法
Object.keys(nodeCreateContentsMethods).forEach(item => {
proto[item] = nodeCreateContentsMethods[item]
})
// 协同相关
if (this.mindMap.cooperate) {
Object.keys(nodeCooperateMethods).forEach(item => {
proto[item] = nodeCooperateMethods[item]
})
}
proto.bindEvent = true
}
// 初始化
this.getSize()
@@ -195,10 +205,7 @@ class Node {
}
// 如果没有返回内容,那么还是使用内置的节点内容
if (this._customNodeContent) {
this._customNodeContent.setAttribute(
'xmlns',
'http://www.w3.org/1999/xhtml'
)
addXmlns(this._customNodeContent)
return
}
this._imgData = this.createImgNode()
@@ -211,9 +218,15 @@ class Node {
this._prefixData = createNodePrefixContent
? createNodePrefixContent(this)
: null
if (this._prefixData && this._prefixData.el) {
addXmlns(this._prefixData.el)
}
this._postfixData = createNodePostfixContent
? createNodePostfixContent(this)
: null
if (this._postfixData && this._postfixData.el) {
addXmlns(this._postfixData.el)
}
}
// 计算节点的宽高
@@ -521,7 +534,7 @@ class Node {
}
}
// 多选和取消多选
if ((e.ctrlKey || e.metaKey) && enableCtrlKeyNodeSelection) {
if (!readonly && (e.ctrlKey || e.metaKey) && enableCtrlKeyNodeSelection) {
this.isMultipleChoice = true
let isActive = this.getData('isActive')
if (!isActive)
@@ -773,9 +786,9 @@ class Node {
if (this.nodeData.inserting) {
delete this.nodeData.inserting
this.active()
setTimeout(() => {
this.mindMap.emit('node_dblclick', this, null, true)
}, 0)
// setTimeout(() => {
this.mindMap.emit('node_dblclick', this, null, true)
// }, 0)
}
}
@@ -1175,6 +1188,19 @@ class Node {
closeHighlight() {
if (this.group) this.group.removeClass('smm-node-highlight')
}
// 伪克隆节点
// 克隆出的节点并不能真正当做一个节点使用
fakeClone() {
const newNode = new Node({
...this.opt,
uid: createUid()
})
Object.keys(this).forEach(item => {
newNode[item] = this[item]
})
return newNode
}
}
export default Node

View File

@@ -5,12 +5,12 @@ import {
addHtmlStyle,
checkIsRichText,
isUndef,
createForeignObjectNode
createForeignObjectNode,
addXmlns
} 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'
import { defenseXSS } from '../../../utils/xss'
// 创建图片节点
function createImgNode() {
@@ -142,7 +142,7 @@ function createRichTextNode() {
text: text
})
}
let html = `<div>${defenseXSS(this.getData('text'))}</div>`
let html = `<div>${this.getData('text')}</div>`
if (!this.mindMap.commonCaches.measureRichtextNodeTextSizeEl) {
this.mindMap.commonCaches.measureRichtextNodeTextSizeEl =
document.createElement('div')
@@ -158,7 +158,7 @@ function createRichTextNode() {
div.innerHTML = html
let el = div.children[0]
el.classList.add('smm-richtext-node-wrap')
el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
addXmlns(el)
el.style.maxWidth = textAutoWrapWidth + 'px'
let { width, height } = el.getBoundingClientRect()
// 如果文本为空,那么需要计算一个默认高度

View File

@@ -29,8 +29,9 @@ class View {
this.fit()
})
// 拖动视图
this.mindMap.event.on('mousedown', () => {
this.mindMap.event.on('mousedown', e => {
if (this.mindMap.opt.isDisableDrag) return
e.preventDefault()
this.sx = this.x
this.sy = this.y
})

View File

@@ -15,7 +15,7 @@ import {
} from '../utils/xmind'
// 解析.xmind文件
const parseXmindFile = file => {
const parseXmindFile = (file, handleMultiCanvas) => {
return new Promise((resolve, reject) => {
JSZip.loadAsync(file).then(
async zip => {
@@ -25,7 +25,7 @@ const parseXmindFile = file => {
let xmlFile = zip.files['content.xml'] || zip.files['/content.xml']
if (jsonFile) {
let json = await jsonFile.async('string')
content = await transformXmind(json, zip.files)
content = await transformXmind(json, zip.files, handleMultiCanvas)
} else if (xmlFile) {
let xml = await xmlFile.async('string')
let json = xmlConvert.xml2json(xml)
@@ -48,8 +48,15 @@ const parseXmindFile = file => {
}
// 转换xmind数据
const transformXmind = async (content, files) => {
const data = JSON.parse(content)[0]
const transformXmind = async (content, files, handleMultiCanvas) => {
content = JSON.parse(content)
let data = null
if (content.length > 1 && typeof handleMultiCanvas === 'function') {
data = await handleMultiCanvas(content)
}
if (!data) {
data = content[0]
}
const nodeTree = data.rootTopic
const newTree = {}
const waitLoadImageList = []

View File

@@ -5,6 +5,7 @@ import {
getNodeIndexInNodeList
} from '../utils'
import Base from '../layouts/Base'
import { CONSTANTS } from '../constants/constant'
// 节点拖动插件
class Drag extends Base {
@@ -38,6 +39,10 @@ class Drag extends Base {
this.clone = null
// 同级位置占位符
this.placeholder = null
this.placeholderWidth = 50
this.placeholderHeight = 10
this.placeHolderLine = null
this.placeHolderExtraLines = []
// 鼠标按下位置和节点左上角的偏移量
this.offsetX = 0
this.offsetY = 0
@@ -276,6 +281,7 @@ class Drag extends Base {
const {
dragMultiNodeRectConfig,
dragPlaceholderRectFill,
dragPlaceholderLineConfig,
dragOpacityConfig
} = this.mindMap.opt
const {
@@ -309,9 +315,19 @@ class Drag extends Base {
this.clone.opacity(dragOpacityConfig.cloneNodeOpacity)
this.clone.css('z-index', 99999)
// 同级位置提示元素
this.placeholder = this.mindMap.otherDraw.rect().fill({
color: dragPlaceholderRectFill || lineColor
})
this.placeholder = this.mindMap.otherDraw
.rect()
.fill({
color: dragPlaceholderRectFill || lineColor
})
.radius(5)
this.placeHolderLine = this.mindMap.otherDraw
.path()
.stroke({
color: dragPlaceholderLineConfig.color || lineColor,
width: dragPlaceholderLineConfig.width
})
.fill({ color: 'none' })
// 当前被拖拽的节点的临时设置
this.beingDragNodeList.forEach(node => {
// 降低透明度
@@ -331,6 +347,16 @@ class Drag extends Base {
}
this.clone.remove()
this.placeholder.remove()
this.placeHolderLine.remove()
this.removeExtraLines()
}
// 移除额外创建的连线
removeExtraLines() {
this.placeHolderExtraLines.forEach(item => {
item.remove()
})
this.placeHolderExtraLines = []
}
// 检测重叠节点
@@ -338,10 +364,22 @@ class Drag extends Base {
if (!this.drawTransform || !this.placeholder) {
return
}
const {
LOGICAL_STRUCTURE,
MIND_MAP,
ORGANIZATION_STRUCTURE,
CATALOG_ORGANIZATION,
TIMELINE,
TIMELINE2,
VERTICAL_TIMELINE,
FISHBONE
} = CONSTANTS.LAYOUT
this.overlapNode = null
this.prevNode = null
this.nextNode = null
this.placeholder.size(0, 0)
this.placeHolderLine.hide()
this.removeExtraLines()
this.nodeList.forEach(node => {
if (node.getData('isActive')) {
this.mindMap.execCommand('SET_NODE_ACTIVE', node, false)
@@ -350,52 +388,310 @@ class Drag extends Base {
return
}
switch (this.mindMap.opt.layout) {
case 'logicalStructure':
case LOGICAL_STRUCTURE:
this.handleLogicalStructure(node)
break
case 'mindMap':
case MIND_MAP:
this.handleMindMap(node)
break
case 'organizationStructure':
case ORGANIZATION_STRUCTURE:
this.handleOrganizationStructure(node)
break
case 'catalogOrganization':
case CATALOG_ORGANIZATION:
this.handleCatalogOrganization(node)
break
case 'timeline':
case TIMELINE:
this.handleTimeLine(node)
break
case 'timeline2':
case TIMELINE2:
this.handleTimeLine2(node)
break
case 'verticalTimeline':
case VERTICAL_TIMELINE:
this.handleLogicalStructure(node)
break
case 'fishbone':
case FISHBONE:
this.handleFishbone(node)
break
default:
this.handleLogicalStructure(node)
}
})
// 重叠节点,也就是添加为子节点
if (this.overlapNode) {
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
this.handleOverlapNode()
}
}
// 处理作为子节点的情况
handleOverlapNode() {
const {
LOGICAL_STRUCTURE,
MIND_MAP,
ORGANIZATION_STRUCTURE,
CATALOG_ORGANIZATION,
TIMELINE,
TIMELINE2,
VERTICAL_TIMELINE,
FISHBONE
} = CONSTANTS.LAYOUT
const { LEFT, TOP, RIGHT, BOTTOM } = CONSTANTS.LAYOUT_GROW_DIR
const layerIndex = this.overlapNode.layerIndex
const children = this.overlapNode.children
const marginX = this.mindMap.renderer.layout.getMarginX(layerIndex + 1)
const marginY = this.mindMap.renderer.layout.getMarginY(layerIndex + 1)
const halfPlaceholderWidth = this.placeholderWidth / 2
const halfPlaceholderHeight = this.placeholderHeight / 2
let dir = ''
let x = ''
let y = ''
let rotate = false
let notRenderPlaceholder = false
// 目标节点存在子节点,那么基于最后一个子节点定位
if (children.length > 0) {
const lastChild = children[children.length - 1]
const lastNodeRect = this.getNodeRect(lastChild)
dir = this.getNewChildNodeDir(lastChild)
switch (this.mindMap.opt.layout) {
case LOGICAL_STRUCTURE:
case MIND_MAP:
x =
dir === LEFT
? lastNodeRect.originRight - this.placeholderWidth
: lastNodeRect.originLeft
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
break
case ORGANIZATION_STRUCTURE:
rotate = true
x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
y = lastNodeRect.originTop
break
case CATALOG_ORGANIZATION:
if (layerIndex === 0) {
rotate = true
x =
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
y = lastNodeRect.originTop
} else {
x = lastNodeRect.originLeft
y =
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
}
break
case TIMELINE:
if (layerIndex === 0) {
rotate = true
x =
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
y =
lastNodeRect.originTop +
lastNodeRect.originHeight / 2 -
halfPlaceholderWidth
} else {
x = lastNodeRect.originLeft
y =
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
}
break
case TIMELINE2:
if (layerIndex === 0) {
rotate = true
x =
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
y =
lastNodeRect.originTop +
lastNodeRect.originHeight / 2 -
halfPlaceholderWidth
} else {
x = lastNodeRect.originLeft
if (layerIndex === 1) {
y =
dir === TOP
? lastNodeRect.originTop -
this.placeholderHeight -
this.minOffset +
halfPlaceholderHeight
: lastNodeRect.originBottom +
this.minOffset -
halfPlaceholderHeight
} else {
y =
lastNodeRect.originBottom +
this.minOffset -
halfPlaceholderHeight
}
}
break
case VERTICAL_TIMELINE:
if (layerIndex === 0) {
x =
lastNodeRect.originLeft +
lastNodeRect.originWidth / 2 -
halfPlaceholderWidth
y =
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
} else {
x =
dir === RIGHT
? lastNodeRect.originLeft
: lastNodeRect.originRight - this.placeholderWidth
y =
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
}
break
case FISHBONE:
if (layerIndex <= 1) {
notRenderPlaceholder = true
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
} else {
x = lastNodeRect.originLeft
y =
dir === TOP
? lastNodeRect.originBottom +
this.minOffset -
halfPlaceholderHeight
: lastNodeRect.originTop -
this.placeholderHeight -
this.minOffset +
halfPlaceholderHeight
}
break
default:
}
} else {
// 目标节点不存在子节点,那么基于目标节点定位
const nodeRect = this.getNodeRect(this.overlapNode)
dir = this.getNewChildNodeDir(this.overlapNode)
switch (this.mindMap.opt.layout) {
case LOGICAL_STRUCTURE:
case MIND_MAP:
x =
dir === RIGHT
? nodeRect.originRight + marginX
: nodeRect.originLeft - this.placeholderWidth - marginX
y =
nodeRect.originTop +
(nodeRect.originHeight - this.placeholderHeight) / 2
break
case ORGANIZATION_STRUCTURE:
rotate = true
x =
nodeRect.originLeft +
(nodeRect.originWidth - this.placeholderHeight) / 2
y = nodeRect.originBottom + marginX
break
case CATALOG_ORGANIZATION:
if (layerIndex === 0) {
rotate = true
}
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
y = nodeRect.originBottom + marginX
break
case TIMELINE:
if (layerIndex === 0) {
rotate = true
}
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
y = nodeRect.originBottom + marginY
break
case TIMELINE2:
if (layerIndex === 0) {
rotate = true
}
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
if (layerIndex === 1) {
y =
dir === TOP
? nodeRect.originTop - this.placeholderHeight - marginX
: nodeRect.originBottom + marginX
} else {
y = nodeRect.originBottom + marginX
}
break
case VERTICAL_TIMELINE:
if (layerIndex === 0) {
rotate = true
}
x =
dir === RIGHT
? nodeRect.originRight + marginX
: nodeRect.originLeft - this.placeholderWidth - marginX
y =
nodeRect.originTop +
nodeRect.originHeight / 2 -
halfPlaceholderHeight
break
case FISHBONE:
if (layerIndex <= 1) {
notRenderPlaceholder = true
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
} else {
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
y =
dir === BOTTOM
? nodeRect.originTop -
this.placeholderHeight -
this.minOffset +
halfPlaceholderHeight
: nodeRect.originBottom + this.minOffset - halfPlaceholderHeight
}
break
default:
}
}
if (!notRenderPlaceholder) {
this.setPlaceholderRect({
x,
y,
dir,
rotate
})
}
}
// 获取节点的生长方向
getNewChildNodeDir(node) {
const {
LOGICAL_STRUCTURE,
MIND_MAP,
TIMELINE2,
VERTICAL_TIMELINE,
FISHBONE
} = CONSTANTS.LAYOUT
switch (this.mindMap.opt.layout) {
case LOGICAL_STRUCTURE:
return CONSTANTS.LAYOUT_GROW_DIR.RIGHT
case MIND_MAP:
case TIMELINE2:
case VERTICAL_TIMELINE:
case FISHBONE:
return node.dir
default:
return ''
}
}
// 垂直方向比较
// isReverse是否反向
handleVerticalCheck(node, checkList, isReverse = false) {
let x = this.mouseMoveX
let y = this.mouseMoveY
let nodeRect = this.getNodeRect(node)
if (isReverse) {
const { layout } = this.mindMap.opt
const { LAYOUT, LAYOUT_GROW_DIR } = CONSTANTS
const { VERTICAL_TIMELINE, FISHBONE } = LAYOUT
const { BOTTOM, LEFT } = LAYOUT_GROW_DIR
const mouseMoveX = this.mouseMoveX
const mouseMoveY = this.mouseMoveY
const nodeRect = this.getNodeRect(node)
const dir = this.getNewChildNodeDir(node)
const layerIndex = node.layerIndex
if (
isReverse ||
(layout === FISHBONE && dir === BOTTOM && layerIndex >= 3)
) {
checkList = checkList.reverse()
}
let oneFourthHeight = nodeRect.height / 4
let oneFourthHeight = nodeRect.originHeight / 4
let { prevBrotherOffset, nextBrotherOffset } =
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'v')
if (nodeRect.left <= x && nodeRect.right >= x) {
if (nodeRect.left <= mouseMoveX && nodeRect.right >= mouseMoveX) {
// 检测兄弟节点位置
if (
!this.overlapNode &&
@@ -405,38 +701,92 @@ class Drag extends Base {
) {
let checkIsPrevNode =
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
? y > nodeRect.bottom && y <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点外底部判断
: y >= nodeRect.bottom - oneFourthHeight && y <= nodeRect.bottom // 否则在当前节点底部1/4区间判断
? mouseMoveY > nodeRect.bottom &&
mouseMoveY <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点底部判断
: mouseMoveY >= nodeRect.bottom - oneFourthHeight &&
mouseMoveY <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
let checkIsNextNode =
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
? y < nodeRect.top && y >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
: y >= nodeRect.top && y <= nodeRect.top + oneFourthHeight
? mouseMoveY < nodeRect.top &&
mouseMoveY >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
: mouseMoveY >= nodeRect.top &&
mouseMoveY <= nodeRect.top + oneFourthHeight
const { scaleY } = this.drawTransform
let x =
dir === LEFT
? nodeRect.originRight - this.placeholderWidth
: nodeRect.originLeft
let notRenderLine = false
switch (layout) {
case VERTICAL_TIMELINE:
if (layerIndex === 1) {
x =
nodeRect.originLeft +
nodeRect.originWidth / 2 -
this.placeholderWidth / 2
}
break
default:
}
if (checkIsPrevNode) {
if (isReverse) {
this.nextNode = node
} else {
this.prevNode = node
}
let size = this.formatPlaceholderSize(nextBrotherOffset)
this.setPlaceholderRect(
node.width,
size,
nodeRect.originLeft,
nodeRect.originBottom
)
let y =
nodeRect.originBottom +
nextBrotherOffset / scaleY - //nextBrotherOffset已经是实际间距的一半了
this.placeholderHeight / 2
switch (layout) {
case FISHBONE:
if (layerIndex === 2) {
notRenderLine = true
y =
nodeRect.originBottom +
this.minOffset -
this.placeholderHeight / 2
}
break
default:
}
this.setPlaceholderRect({
x,
y,
dir,
notRenderLine
})
} else if (checkIsNextNode) {
if (isReverse) {
this.prevNode = node
} else {
this.nextNode = node
}
let size = this.formatPlaceholderSize(prevBrotherOffset)
this.setPlaceholderRect(
node.width,
size,
nodeRect.originLeft,
nodeRect.originTop - size
)
let y =
nodeRect.originTop -
this.placeholderHeight -
prevBrotherOffset / scaleY +
this.placeholderHeight / 2
switch (layout) {
case FISHBONE:
if (layerIndex === 2) {
notRenderLine = true
y =
nodeRect.originTop -
this.placeholderHeight -
this.minOffset +
this.placeholderHeight / 2
}
break
default:
}
this.setPlaceholderRect({
x,
y,
dir,
notRenderLine
})
}
}
// 检测是否重叠
@@ -446,7 +796,7 @@ class Drag extends Base {
prevBrotherOffset,
nextBrotherOffset,
size: oneFourthHeight,
pos: y,
pos: mouseMoveY,
nodeRect
})
}
@@ -454,13 +804,16 @@ class Drag extends Base {
// 水平方向比较
handleHorizontalCheck(node, checkList) {
let x = this.mouseMoveX
let y = this.mouseMoveY
const { layout } = this.mindMap.opt
const { LAYOUT } = CONSTANTS
const { FISHBONE, TIMELINE, TIMELINE2 } = LAYOUT
let mouseMoveX = this.mouseMoveX
let mouseMoveY = this.mouseMoveY
let nodeRect = this.getNodeRect(node)
let oneFourthWidth = nodeRect.width / 4
let oneFourthWidth = nodeRect.originWidth / 4
let { prevBrotherOffset, nextBrotherOffset } =
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'h')
if (nodeRect.top <= y && nodeRect.bottom >= y) {
if (nodeRect.top <= mouseMoveY && nodeRect.bottom >= mouseMoveY) {
// 检测兄弟节点位置
if (
!this.overlapNode &&
@@ -470,30 +823,62 @@ class Drag extends Base {
) {
let checkIsPrevNode =
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
? x < nodeRect.right + nextBrotherOffset && x >= nodeRect.right // 那么在当前节点外底部判断
: x <= nodeRect.right && x >= nodeRect.right - oneFourthWidth // 否则在当前节点底部1/4区间判断
? mouseMoveX < nodeRect.right + nextBrotherOffset &&
mouseMoveX >= nodeRect.right // 那么在当前节点底部判断
: mouseMoveX <= nodeRect.right &&
mouseMoveX >= nodeRect.right - oneFourthWidth // 否则在当前节点内底部1/4区间判断
let checkIsNextNode =
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
? x > nodeRect.left - prevBrotherOffset && x <= nodeRect.left // 那么在当前节点外底部判断
: x <= nodeRect.left + oneFourthWidth && x >= nodeRect.left
? mouseMoveX > nodeRect.left - prevBrotherOffset &&
mouseMoveX <= nodeRect.left // 那么在当前节点外底部判断
: mouseMoveX <= nodeRect.left + oneFourthWidth &&
mouseMoveX >= nodeRect.left
const { scaleX } = this.drawTransform
const layerIndex = node.layerIndex
let y = nodeRect.originTop
let notRenderLine = false
switch (layout) {
case TIMELINE:
case TIMELINE2:
y =
nodeRect.originTop +
nodeRect.originHeight / 2 -
this.placeholderWidth / 2
break
case FISHBONE:
if (layerIndex === 1) {
notRenderLine = true
y =
nodeRect.originTop +
nodeRect.originHeight / 2 -
this.placeholderWidth / 2
}
break
default:
}
if (checkIsPrevNode) {
this.prevNode = node
let size = this.formatPlaceholderSize(nextBrotherOffset)
this.setPlaceholderRect(
size,
node.height,
nodeRect.originRight,
nodeRect.originTop
)
this.setPlaceholderRect({
x:
nodeRect.originRight +
nextBrotherOffset / scaleX - //nextBrotherOffset已经是实际间距的一半了
this.placeholderHeight / 2,
y,
rotate: true,
notRenderLine
})
} else if (checkIsNextNode) {
this.nextNode = node
let size = this.formatPlaceholderSize(prevBrotherOffset)
this.setPlaceholderRect(
size,
node.height,
nodeRect.originLeft - size,
nodeRect.originTop
)
this.setPlaceholderRect({
x:
nodeRect.originLeft -
this.placeholderHeight -
prevBrotherOffset / scaleX +
this.placeholderHeight / 2,
y,
rotate: true,
notRenderLine
})
}
}
// 检测是否重叠
@@ -503,7 +888,7 @@ class Drag extends Base {
prevBrotherOffset,
nextBrotherOffset,
size: oneFourthWidth,
pos: x,
pos: mouseMoveX,
nodeRect
})
}
@@ -511,8 +896,12 @@ class Drag extends Base {
// 获取节点距前一个和后一个节点的距离
getNodeDistanceToSiblingNode(checkList, node, nodeRect, dir) {
let dir1 = dir === 'v' ? 'top' : 'left'
let dir2 = dir === 'v' ? 'bottom' : 'right'
const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
let { scaleX, scaleY } = this.drawTransform
let dir1 = dir === 'v' ? TOP : LEFT
let dir2 = dir === 'v' ? BOTTOM : RIGHT
let scale = dir === 'v' ? scaleY : scaleX
let minOffset = this.minOffset * scale
let index = getNodeIndexInNodeList(node, checkList)
let prevBrother = null
let nextBrother = null
@@ -531,10 +920,10 @@ class Drag extends Base {
prevBrotherOffset = nodeRect[dir1] - prevNodeRect[dir2]
// 间距小于10就当它不存在
prevBrotherOffset =
prevBrotherOffset >= this.minOffset ? prevBrotherOffset / 2 : 0
prevBrotherOffset >= minOffset ? prevBrotherOffset / 2 : 0
} else {
// 没有前一个兄弟节点那么假设和前一个节点的距离为20
prevBrotherOffset = this.minOffset
prevBrotherOffset = minOffset
}
// 和后一个兄弟节点的距离
let nextBrotherOffset = 0
@@ -542,25 +931,70 @@ class Drag extends Base {
let nextNodeRect = this.getNodeRect(nextBrother)
nextBrotherOffset = nextNodeRect[dir1] - nodeRect[dir2]
nextBrotherOffset =
nextBrotherOffset >= this.minOffset ? nextBrotherOffset / 2 : 0
nextBrotherOffset >= minOffset ? nextBrotherOffset / 2 : 0
} else {
nextBrotherOffset = this.minOffset
nextBrotherOffset = minOffset
}
return {
prevBrother,
prevBrotherOffset,
nextBrother,
nextBrotherOffset
}
}
// 处理提示元素的大小
formatPlaceholderSize(size) {
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
return size > 0 ? Math.min(size, nodeDragPlaceholderMaxSize) : 5
}
// 设置提示元素的大小和位置
setPlaceholderRect(w, h, x, y) {
setPlaceholderRect({ x, y, dir, rotate, notRenderLine }) {
let w = this.placeholderWidth
let h = this.placeholderHeight
if (rotate) {
const tmp = w
w = h
h = tmp
}
this.placeholder.size(w, h).move(x, y)
if (notRenderLine) {
return
}
const { dragPlaceholderLineConfig } = this.mindMap.opt
let node = null
let parent = null
if (this.overlapNode) {
node = this.overlapNode
parent = this.overlapNode
} else {
node = this.prevNode || this.nextNode
parent = node.parent
}
parent = parent.fakeClone()
node = node.fakeClone()
const tmpNode = this.beingDragNodeList[0].fakeClone()
tmpNode.dir = dir
tmpNode.left = x
tmpNode.top = y
tmpNode.width = w
tmpNode.height = h
parent.children = [tmpNode]
parent._lines = []
this.placeHolderLine.show()
this.mindMap.renderer.layout.renderLine(
parent,
[this.placeHolderLine],
(...args) => {
// node.styleLine(...args)
},
node.style.getStyle('lineStyle', true)
)
this.placeHolderExtraLines = [...parent._lines]
this.placeHolderExtraLines.forEach(line => {
this.mindMap.otherDraw.add(line)
line
.stroke({
color: dragPlaceholderLineConfig.color,
width: dragPlaceholderLineConfig.width
})
.fill({ color: 'none' })
})
}
// 检测是否重叠
@@ -573,8 +1007,9 @@ class Drag extends Base {
pos,
nodeRect
}) {
let dir1 = dir === 'v' ? 'top' : 'left'
let dir2 = dir === 'v' ? 'bottom' : 'right'
const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
let dir1 = dir === 'v' ? TOP : LEFT
let dir2 = dir === 'v' ? BOTTOM : RIGHT
if (!this.overlapNode && !this.prevNode && !this.nextNode) {
if (
nodeRect[dir1] + (prevBrotherOffset > 0 ? 0 : size) <= pos &&
@@ -638,7 +1073,7 @@ class Drag extends Base {
this.handleHorizontalCheck(node, checkList)
} else {
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
if (node.dir === 'top' && node.layerIndex === 2) {
if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
this.handleVerticalCheck(node, checkList, true)
} else {
this.handleVerticalCheck(node, checkList)
@@ -657,7 +1092,7 @@ class Drag extends Base {
this.handleHorizontalCheck(node, checkList)
} else {
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
if (node.dir === 'top' && node.layerIndex === 2) {
if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
this.handleVerticalCheck(node, checkList, true)
} else {
this.handleVerticalCheck(node, checkList)
@@ -678,6 +1113,8 @@ class Drag extends Base {
getNodeRect(node) {
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
let { left, top, width, height } = node
let originWidth = width
let originHeight = height
let originLeft = left
let originTop = top
let originBottom = top + height
@@ -687,12 +1124,12 @@ class Drag extends Base {
left = left * scaleX + translateX
top = top * scaleY + translateY
return {
width,
height,
left,
top,
right,
bottom,
originWidth,
originHeight,
originLeft,
originTop,
originBottom,

View File

@@ -10,9 +10,18 @@ class Formula {
this.opt = opt
this.mindMap = opt.mindMap
window.katex = katex
this.init()
this.extendQuill()
}
init() {
if (this.mindMap.opt.enableEditFormulaInRichTextEdit) {
this.mindMap.opt.transformRichTextOnEnterEdit =
this.latexRichToText.bind(this)
this.mindMap.opt.beforeHideRichTextEdit = this.formatLatex.bind(this)
}
}
// 获取katex配置
getKatexConfig() {
const config = {
@@ -59,6 +68,74 @@ class Formula {
richTextPlugin.setTextStyleIfNotRichText(richTextPlugin.node)
richTextPlugin.hideEditText([node])
}
// 将公式富文本转换为公式源码
latexRichToText(nodeText) {
if (nodeText.indexOf('class="ql-formula"') !== -1) {
const parser = new DOMParser()
const doc = parser.parseFromString(nodeText, 'text/html')
const els = doc.getElementsByClassName('ql-formula')
for (const el of els)
nodeText = nodeText.replace(
el.outerHTML,
`\$${el
.getAttribute('data-value')
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')}\$`
)
}
return nodeText
}
// 使用格式化的 latex 字符串内容更新 quill 内容:输入 $*****$
formatLatex(richText) {
const contents = richText.quill.getContents()
const ops = contents.ops
let mod = false
for (let i = ops.length - 1; i >= 0; i--) {
const op = ops[i]
const insert = op.insert
if (insert && typeof insert !== 'object' && insert !== '\n') {
if (/\$.+?\$/g.test(insert)) {
const m = [...insert.matchAll(/\$.+?\$/g)]
const arr = insert.split(/\$.+?\$/g)
for (let j = m.length - 1; j >= 0; j--) {
const exp = m[j]?.[0].slice(1, -1) ?? null // $...$ 之间的表达式
if (exp !== null && exp.trim().length > 0) {
const isLegal = this.checkFormulaIsLegal(exp)
if (isLegal) {
arr.splice(j + 1, 0, { insert: { formula: exp } }) // 添加到对应位置之后
mod = true
} else {
arr.splice(j + 1, 0, '')
}
} else arr.splice(j + 1, 0, '') // 表达式为空时,占位
}
while (arr.length > 0) {
let v = arr.pop()
if (typeof v === 'string') {
if (v.length < 1) continue
v = { insert: v }
}
v['attributes'] = ops[i]['attributes']
ops.splice(i + 1, 0, v)
}
ops.splice(i, 1) // 删除原来的字符串
}
}
}
if (mod) richText.quill.setContents(contents)
}
checkFormulaIsLegal(str) {
try {
katex.renderToString(str)
return true
} catch (e) {
return false
}
}
}
Formula.instanceName = 'formula'

View File

@@ -154,6 +154,7 @@ class NodeImgAdjust {
})
btnEl.addEventListener('mousedown', e => {
e.stopPropagation()
e.preventDefault()
this.onMousedown(e)
})
btnEl.addEventListener('mouseup', e => {

View File

@@ -9,7 +9,8 @@ import {
isUndef,
checkSmmFormatData,
removeHtmlNodeByClass,
formatGetNodeGeneralization
formatGetNodeGeneralization,
nodeRichTextToTextWithWrap
} from '../utils'
import { CONSTANTS } from '../constants/constant'
@@ -170,7 +171,8 @@ class RichText {
customInnerElsAppendTo,
nodeTextEditZIndex,
textAutoWrapWidth,
selectTextOnEnterEditText
selectTextOnEnterEditText,
transformRichTextOnEnterEdit
} = this.mindMap.opt
this.node = node
this.isInserting = isInserting
@@ -240,7 +242,10 @@ class RichText {
}
}
// 节点文本内容
const nodeText = node.getData('text')
let nodeText = node.getData('text')
if (typeof transformRichTextOnEnterEdit === 'function') {
nodeText = transformRichTextOnEnterEdit(nodeText)
}
// 是否是空文本
const isEmptyText = isUndef(nodeText)
// 是否是非空的非富文本
@@ -312,7 +317,9 @@ class RichText {
getEditText() {
let html = this.quill.container.firstChild.innerHTML
// 去除ql-cursor节点
html = removeHtmlNodeByClass(html, '.ql-cursor')
// https://github.com/wanglin2/mind-map/commit/138cc4b3e824671143f0bf70e5c46796f48520d0
// https://github.com/wanglin2/mind-map/commit/0760500cebe8ec4e8ad84ab63f877b8b2a193aa1
// html = removeHtmlNodeByClass(html, '.ql-cursor')
// 去除最后的空行
return html.replace(/<p><br><\/p>$/, '')
}
@@ -322,6 +329,10 @@ class RichText {
if (!this.showTextEdit) {
return
}
const { beforeHideRichTextEdit } = this.mindMap.opt
if (typeof beforeHideRichTextEdit === 'function') {
beforeHideRichTextEdit(this)
}
let html = this.getEditText()
let list =
nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
@@ -365,6 +376,21 @@ class RichText {
},
theme: 'snow'
})
// 拦截粘贴事件
this.quill.root.addEventListener('copy', event => {
event.preventDefault()
const sel = window.getSelection()
const originStr = sel.toString()
try {
const range = sel.getRangeAt(0)
const div = document.createElement('div')
div.appendChild(range.cloneContents())
const text = nodeRichTextToTextWithWrap(div.innerHTML)
event.clipboardData.setData('text/plain', text)
} catch (e) {
event.clipboardData.setData('text/plain', originStr)
}
})
this.quill.on('selection-change', range => {
// 刚创建的节点全选不需要显示操作条
if (this.isInserting) return

View File

@@ -16,10 +16,12 @@ class TouchEvent {
this.onTouchmove = this.onTouchmove.bind(this)
this.onTouchcancel = this.onTouchcancel.bind(this)
this.onTouchend = this.onTouchend.bind(this)
window.addEventListener('touchstart', this.onTouchstart)
window.addEventListener('touchmove', this.onTouchmove)
window.addEventListener('touchcancel', this.onTouchcancel)
window.addEventListener('touchend', this.onTouchend)
window.addEventListener('touchstart', this.onTouchstart, { passive: false })
window.addEventListener('touchmove', this.onTouchmove, { passive: false })
window.addEventListener('touchcancel', this.onTouchcancel, {
passive: false
})
window.addEventListener('touchend', this.onTouchend, { passive: false })
}
// 解绑事件
@@ -32,6 +34,7 @@ class TouchEvent {
// 手指按下事件
onTouchstart(e) {
e.preventDefault()
this.touchesNum = e.touches.length
this.touchStartScaleView = null
if (this.touchesNum === 1) {
@@ -43,6 +46,7 @@ class TouchEvent {
// 手指移动事件
onTouchmove(e) {
e.preventDefault()
let len = e.touches.length
if (len === 1) {
let touch = e.touches[0]
@@ -103,6 +107,7 @@ class TouchEvent {
// 手指松开事件
onTouchend(e) {
e.preventDefault()
this.dispatchMouseEvent('mouseup', e.target)
if (this.touchesNum === 1) {
// 模拟双击事件

View File

@@ -41,10 +41,21 @@ class Watermark {
// 创建水印容器
createContainer() {
if (this.watermarkDraw) return
this.watermarkDraw = this.mindMap.svg
.group()
this.watermarkDraw = new G()
.css({ 'pointer-events': 'none', 'user-select': 'none' })
.addClass('smm-water-mark-container')
this.updateLayer()
}
// 更新水印容器层级
updateLayer() {
if (!this.watermarkDraw) return
const { belowNode } = this.mindMap.opt.watermarkConfig
if (belowNode) {
this.watermarkDraw.insertBefore(this.mindMap.draw)
} else {
this.mindMap.svg.add(this.watermarkDraw)
}
}
// 删除水印容器
@@ -160,6 +171,7 @@ class Watermark {
this.mindMap.opt.watermarkConfig,
config
)
this.updateLayer()
this.handleConfig(config)
this.draw()
}
@@ -167,11 +179,13 @@ class Watermark {
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
this.removeContainer()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()
this.removeContainer()
}
}

View File

@@ -1335,7 +1335,7 @@ export const handleGetSvgDataExtraContent = ({
if (!res) return
const { el, cssText, height } = res
if (el instanceof HTMLElement) {
el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
addXmlns(el)
const foreignObject = createForeignObjectNode({ el, height })
callback(foreignObject, height)
}
@@ -1476,3 +1476,57 @@ export const formatGetNodeGeneralization = data => {
return []
}
}
/**
* 防御 XSS 攻击,过滤恶意 HTML 标签和属性
* @param {string} text 需要过滤的文本
* @returns {string} 过滤后的文本
*/
export const defenseXSS = text => {
text = String(text)
// 初始化结果变量
let result = text
// 使用正则表达式匹配 HTML 标签
const match = text.match(/<(\S*?)[^>]*>.*?|<.*? \/>/g)
if (match == null) {
// 如果没有匹配到任何标签,则直接返回原始文本
return text
}
// 遍历匹配到的标签
for (let value of match) {
// 定义白名单属性正则表达式style、target、href
const whiteAttrRegex = new RegExp(/(style|target|href)=["'][^"']*["']/g)
// 定义黑名单href正则表达式javascript:
const aHrefBlackRegex = new RegExp(/href=["']javascript:/g)
// 过滤 HTML 标签
const filterHtml = value.replace(
// 匹配属性键值对key="value"
/([a-zA-Z-]+)\s*=\s*["']([^"']*)["']/g,
text => {
// 如果属性值包含黑名单href或不在白名单中则删除该属性
if (aHrefBlackRegex.test(text) || !whiteAttrRegex.test(text)) {
return ''
}
// 否则,保留该属性
return text
}
)
// 将过滤后的标签替换回原始文本
result = result.replace(value, filterHtml)
}
// 返回最终结果
return result
}
// 给节点添加命名空间
export const addXmlns = el => {
el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
}

View File

@@ -1,48 +0,0 @@
/**
* 防御 XSS 攻击,过滤恶意 HTML 标签和属性
* @param {string} text 需要过滤的文本
* @returns {string} 过滤后的文本
*/
export function defenseXSS(text) {
text = String(text)
// 初始化结果变量
let result = text;
// 使用正则表达式匹配 HTML 标签
const match = text.match(/<(\S*?)[^>]*>.*?|<.*? \/>/g);
if (match == null) {
// 如果没有匹配到任何标签,则直接返回原始文本
return text;
}
// 遍历匹配到的标签
for (let value of match) {
// 定义白名单属性正则表达式style、target、href
const whiteAttrRegex = new RegExp(/(style|target|href)=["'][^"']*["']/g);
// 定义黑名单href正则表达式javascript:
const aHrefBlackRegex = new RegExp(/href=["']javascript:/g);
// 过滤 HTML 标签
const filterHtml = value.replace(
// 匹配属性键值对key="value"
/([a-zA-Z-]+)\s*=\s*["']([^"']*)["']/g,
(text) => {
// 如果属性值包含黑名单href或不在白名单中则删除该属性
if (aHrefBlackRegex.test(text) || !whiteAttrRegex.test(text)) {
return "";
}
// 否则,保留该属性
return text;
}
);
// 将过滤后的标签替换回原始文本
result = result.replace(value, filterHtml);
}
// 返回最终结果
return result;
}

View File

@@ -1,10 +1,13 @@
<!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.0,maximum-scale=1.0,minimum-scale=1.0">
<link rel="icon" href="dist/logo.ico">
<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.0,maximum-scale=1.0,minimum-scale=1.0"
/>
<link rel="icon" href="dist/logo.ico" />
<title>思绪思维导图</title>
<script>
// 自定义静态资源的路径
@@ -12,10 +15,26 @@
// 接管应用
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>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
@@ -25,19 +44,19 @@
setTimeout(() => {
resolve({
mindMapData: {
root:{
"data": {
"text": "根节点"
root: {
data: {
text: '根节点'
},
"children": []
children: []
},
theme:{
"template":"avocado",
"config":{}
theme: {
template: 'avocado',
config: {}
},
layout:"logicalStructure",
layout: 'logicalStructure',
config: {},
view: null,
view: null
},
lang: 'zh',
localConfig: null
@@ -45,14 +64,14 @@
}, 200)
})
}
const setTakeOverAppMethods = (data) => {
const setTakeOverAppMethods = data => {
window.takeOverAppMethods = {}
// 获取思维导图数据的函数
window.takeOverAppMethods.getMindMapData = () => {
return data.mindMapData
}
}
// 保存思维导图数据的函数
window.takeOverAppMethods.saveMindMapData = (data) => {
window.takeOverAppMethods.saveMindMapData = data => {
console.log(data)
}
// 获取语言的函数
@@ -60,7 +79,7 @@
return data.lang
}
// 保存语言的函数
window.takeOverAppMethods.saveLanguage = (lang) => {
window.takeOverAppMethods.saveLanguage = lang => {
console.log(lang)
}
// 获取本地配置的函数
@@ -68,7 +87,7 @@
return data.localConfig
}
// 保存本地配置的函数
window.takeOverAppMethods.saveLocalConfig = (config) => {
window.takeOverAppMethods.saveLocalConfig = config => {
console.log(config)
}
}
@@ -79,7 +98,7 @@
// 设置全局的方法
setTakeOverAppMethods(data)
// 思维导图实例创建完成事件
window.$bus.$on('app_inited', (mindMap) => {
window.$bus.$on('app_inited', mindMap => {
console.log(mindMap)
})
// 可以通过window.$bus.$on()来监听应用的一些事件

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -178,6 +178,11 @@ export const backgroundPositionList = [
}
]
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
const ctrl = isMac ? '⌘' : 'Ctrl'
const enter = isMac ? 'Return' : 'Enter'
const macFn = isMac ? 'fn + ' : ''
// 背景图片大小
export const backgroundSizeList = [
{
@@ -207,7 +212,7 @@ export const shortcutKeyList = [
{
icon: 'iconjiedian',
name: 'Insert sibling node',
value: 'Enter'
value: enter
},
{
icon: 'icondodeparent',
@@ -217,17 +222,17 @@ export const shortcutKeyList = [
{
icon: 'iconshangyi',
name: 'Move up node',
value: 'Ctrl + ↑'
value: `${ctrl} + ↑`
},
{
icon: 'iconxiayi',
name: 'Move down node',
value: 'Ctrl + ↓'
value: `${ctrl} + ↓`
},
{
icon: 'icongaikuozonglan',
name: 'Insert summary',
value: 'Ctrl + G'
value: `${ctrl} + G`
},
{
icon: 'iconzhankai',
@@ -247,57 +252,57 @@ export const shortcutKeyList = [
{
icon: 'iconfuzhi',
name: 'Copy node',
value: 'Ctrl + C'
value: `${ctrl} + C`
},
{
icon: 'iconjianqie',
name: 'Cut node',
value: 'Ctrl + X'
value: `${ctrl} + X`
},
{
icon: 'iconniantie',
name: 'Paste node',
value: 'Ctrl + V'
value: `${ctrl} + V`
},
{
icon: 'iconbianji',
name: 'Edit node',
value: 'F2'
value: macFn + 'F2'
},
{
icon: 'iconhuanhang',
name: 'Text Wrap',
value: 'Shift + Enter'
value: `Shift + ${enter}`
},
{
icon: 'iconhoutui-shi',
name: 'Undo',
value: 'Ctrl + Z'
value: `${ctrl} + Z`
},
{
icon: 'iconqianjin1',
name: 'Redo',
value: 'Ctrl + Y'
value: `${ctrl} + Y`
},
{
icon: 'iconquanxuan',
name: 'Select All',
value: 'Ctrl + A'
value: `${ctrl} + A`
},
{
icon: 'iconquanxuan',
name: 'Multiple choice',
value: 'Right click / Ctrl + Left click'
value: `Right click / ${ctrl} + Left click`
},
{
icon: 'iconzhengli',
name: 'Arrange layout',
value: 'Ctrl + L'
value: `${ctrl} + L`
},
{
icon: 'iconsousuo',
name: 'Search and Replace',
value: 'Ctrl + F'
value: `${ctrl} + F`
}
]
},
@@ -307,27 +312,27 @@ export const shortcutKeyList = [
{
icon: 'iconfangda',
name: 'Zoom in',
value: 'Ctrl + +'
value: `${ctrl} + +`
},
{
icon: 'iconsuoxiao',
name: 'Zoom out',
value: 'Ctrl + -'
value: `${ctrl} + -`
},
{
icon: 'iconfangda',
name: 'Zoom in/Zoom out',
value: 'Ctrl + Mouse wheel'
value: `${ctrl} + Mouse wheel`
},
{
icon: 'icondingwei',
name: 'Back root node',
value: 'Ctrl + Enter'
value: `${ctrl} + ${enter}`
},
{
icon: 'iconquanping1',
name: 'fit canvas',
value: 'Ctrl + i'
value: `${ctrl} + i`
}
]
},
@@ -337,7 +342,7 @@ export const shortcutKeyList = [
{
icon: 'iconhuanhang',
name: 'Text Wrap',
value: 'Shift + Enter'
value: `Shift + ${enter}`
},
{
icon: 'iconshanchu',
@@ -352,13 +357,13 @@ export const shortcutKeyList = [
{
icon: 'iconjiedian',
name: 'Insert sibling node',
value: 'Enter'
value: enter
},
{
icon: 'icondodeparent',
name: 'Move up one level',
value: 'Shift + Tab'
},
}
]
}
]
@@ -487,4 +492,4 @@ export const downTypeList = [
icon: 'iconTXT',
desc: 'Plain text file'
}
]
]

View File

@@ -260,6 +260,10 @@ export const backgroundSizeList = [
export const store = {
sidebarZIndex: 1 //侧边栏zIndex
}
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
const ctrl = isMac ? '⌘' : 'Ctrl'
const enter = isMac ? 'Return' : 'Enter'
const macFn = isMac ? 'fn + ' : ''
// 快捷键列表
export const shortcutKeyList = [
@@ -274,7 +278,7 @@ export const shortcutKeyList = [
{
icon: 'iconjiedian',
name: '插入同级节点',
value: 'Enter'
value: enter
},
{
icon: 'icondodeparent',
@@ -284,17 +288,17 @@ export const shortcutKeyList = [
{
icon: 'iconshangyi',
name: '上移节点',
value: 'Ctrl + ↑'
value: `${ctrl} + ↑`
},
{
icon: 'iconxiayi',
name: '下移节点',
value: 'Ctrl + ↓'
value: `${ctrl} + ↓`
},
{
icon: 'icongaikuozonglan',
name: '插入概要',
value: 'Ctrl + G'
value: `${ctrl} + G`
},
{
icon: 'iconzhankai',
@@ -314,57 +318,57 @@ export const shortcutKeyList = [
{
icon: 'iconfuzhi',
name: '复制节点',
value: 'Ctrl + C'
value: `${ctrl} + C`
},
{
icon: 'iconjianqie',
name: '剪切节点',
value: 'Ctrl + X'
value: `${ctrl} + X`
},
{
icon: 'iconniantie',
name: '粘贴节点',
value: 'Ctrl + V'
value: `${ctrl} + V`
},
{
icon: 'iconbianji',
name: '编辑节点',
value: 'F2'
value: macFn + 'F2'
},
{
icon: 'iconhuanhang',
name: '文本换行',
value: 'Shift + Enter'
value: `Shift + ${enter}`
},
{
icon: 'iconhoutui-shi',
name: '回退',
value: 'Ctrl + Z'
value: `${ctrl} + Z`
},
{
icon: 'iconqianjin1',
name: '前进',
value: 'Ctrl + Y'
value: `${ctrl} + Y`
},
{
icon: 'iconquanxuan',
name: '全选',
value: 'Ctrl + A'
value: `${ctrl} + A`
},
{
icon: 'iconquanxuan',
name: '多选',
value: '右键 / Ctrl + 左键'
value: `右键 / ${ctrl} + 左键`
},
{
icon: 'iconzhengli',
name: '一键整理布局',
value: 'Ctrl + L'
value: `${ctrl} + L`
},
{
icon: 'iconsousuo',
name: '搜索和替换',
value: 'Ctrl + F'
value: `${ctrl} + F`
}
]
},
@@ -374,27 +378,27 @@ export const shortcutKeyList = [
{
icon: 'iconfangda',
name: '放大',
value: 'Ctrl + +'
value: `${ctrl} + +`
},
{
icon: 'iconsuoxiao',
name: '缩小',
value: 'Ctrl + -'
value: `${ctrl} + -`
},
{
icon: 'iconfangda',
name: '放大/缩小',
value: 'Ctrl + 鼠标滚动'
value: `${ctrl} + 鼠标滚动`
},
{
icon: 'icondingwei',
name: '回到根节点',
value: 'Ctrl + Enter'
value: `${ctrl} + ${enter}`
},
{
icon: 'iconquanping1',
name: '适应画布',
value: 'Ctrl + i'
value: `${ctrl} + i`
}
]
},
@@ -404,7 +408,7 @@ export const shortcutKeyList = [
{
icon: 'iconhuanhang',
name: '文本换行',
value: 'Shift + Enter'
value: `Shift + ${enter}`
},
{
icon: 'iconshanchu',
@@ -419,7 +423,7 @@ export const shortcutKeyList = [
{
icon: 'iconjiedian',
name: '插入同级节点',
value: 'Enter'
value: enter
},
{
icon: 'icondodeparent',
@@ -582,4 +586,4 @@ export const downTypeList = [
icon: 'iconTXT',
desc: '纯文本文件'
}
]
]

View File

@@ -38,6 +38,7 @@ export default {
watermarkAngle: 'Angle',
watermarkTextOpacity: 'Text opacity',
watermarkTextFontSize: 'Font size',
belowNode: 'Display below nodes',
isEnableNodeRichText: 'Enable node rich text editing',
mousewheelAction: 'Mouse wheel behavior',
zoomView: 'Zoom view',
@@ -151,7 +152,8 @@ export default {
notSelectTip: 'Please select the file to import',
fileContentError: 'The file content is incorrect',
importSuccess: 'Import success',
fileParsingFailed: 'File parsing failed'
fileParsingFailed: 'File parsing failed',
xmindCanvasSelectDialogTitle: 'Select the canvas to import'
},
navigatorToolbar: {
openMiniMap: 'Open mini map',
@@ -275,7 +277,9 @@ export default {
fileOpenFailed: 'File open failed',
defaultFileName: 'Mind map',
creatingTip: 'Creating file',
directory: 'Directory'
directory: 'Directory',
newFileTip: 'Please export the currently edited file before creating a new one, otherwise the content will be lost',
openFileTip: 'Please export the currently edited file before opening it, otherwise the content will be lost'
},
edit: {
newFeatureNoticeTitle: 'New feature reminder',

View File

@@ -38,6 +38,7 @@ export default {
watermarkAngle: '旋转角度',
watermarkTextOpacity: '文字透明度',
watermarkTextFontSize: '文字字号',
belowNode: '显示在节点下方',
isEnableNodeRichText: '是否开启节点富文本编辑',
mousewheelAction: '鼠标滚轮行为',
zoomView: '缩放视图',
@@ -149,7 +150,8 @@ export default {
notSelectTip: '请选择要导入的文件',
fileContentError: '文件内容有误',
importSuccess: '导入成功',
fileParsingFailed: '文件解析失败'
fileParsingFailed: '文件解析失败',
xmindCanvasSelectDialogTitle: '选择要导入的画布'
},
navigatorToolbar: {
openMiniMap: '开启小地图',
@@ -271,7 +273,9 @@ export default {
fileOpenFailed: '文件打开失败',
defaultFileName: '思维导图',
creatingTip: '正在创建文件',
directory: '目录'
directory: '目录',
newFileTip: '新建文件前请先导出当前编辑的文件,否则内容会丢失',
openFileTip: '打开文件前请先导出当前编辑的文件,否则内容会丢'
},
edit: {
newFeatureNoticeTitle: '新特性提醒',

View File

@@ -11,7 +11,7 @@ let langList = [
}
]
let StartList = ['introduction', 'start', 'deploy', 'client', 'translate', 'changelog']
let CourseList = new Array(28).fill(0).map((_, index) => {
let CourseList = new Array(29).fill(0).map((_, index) => {
return 'course' + (index + 1)
})
let APIList = [
@@ -45,7 +45,7 @@ let APIList = [
'markdown',
'utils'
]
let helpList = new Array(5).fill(0).map((_, index) => {
let helpList = new Array(6).fill(0).map((_, index) => {
return 'help' + (index + 1)
})

View File

@@ -1,5 +1,51 @@
# Changelog
## 0.10.0
Major updates: Upgrade the interaction effect when dragging nodes;
Fix:
> 1.Fix the issue where read-only mode can still activate nodes by Ctrl+clicking on them;
>
> 2.Fix the issue of page scaling when setting up scaling in some mobile browsers;
>
> 3.Fix the issue of selecting text when dragging the canvas and adjusting images;
>
> 4.Fix the issue of multiple line breaks when copying node text with line breaks and pasting it;
>
> 5.Fix the issue of displaying blank space when exporting images with custom content before and after nodes;
New:
> 1.Add a new rendering start event node.treeRender_start;
>
> 2.Support displaying watermarks below nodes;
>
> 3.Importing xmind files with multiple canvases supports selecting the specified canvas for import;
>
> 4.Canceling the call to the defenseXSS function has a significant impact on performance; The defenseXSS method is provided as a tool method;
>
> 5.Remove the logic of removing nodes with ql cursor class names from rich text content, and fix the issue of ineffective addition of empty lines when text breaks;
>
> 6.Remove the logic of delayed node editing when inserting new nodes;
>
> 7.Support direct editing of mathematical formulas in rich text editing boxes;
>
> 8.Add demonstration plugins to the packaged file;
Demo
> 1.支持配置水印显示在节点下方;
>
> 2.导入存在多个画布的xmind文件支持选择指定的画布进行导入
>
> 3.优化富文本工具条下拉选项列表高度问题;
>
> 4.新建和打开按钮增加导出的提示,防止内容丢失;
>
> 5.快捷键提示支持区分windows和mac
## 0.9.12
Fix:

View File

@@ -1,6 +1,35 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.10.0</h2>
<p>Major updates: Upgrade the interaction effect when dragging nodes;</p>
<p>Fix:</p>
<blockquote>
<p>1.Fix the issue where read-only mode can still activate nodes by Ctrl+clicking on them;</p>
<p>2.Fix the issue of page scaling when setting up scaling in some mobile browsers;</p>
<p>3.Fix the issue of selecting text when dragging the canvas and adjusting images;</p>
<p>4.Fix the issue of multiple line breaks when copying node text with line breaks and pasting it;</p>
<p>5.Fix the issue of displaying blank space when exporting images with custom content before and after nodes;</p>
</blockquote>
<p>New:</p>
<blockquote>
<p>1.Add a new rendering start event node.treeRender_start;</p>
<p>2.Support displaying watermarks below nodes;</p>
<p>3.Importing xmind files with multiple canvases supports selecting the specified canvas for import;</p>
<p>4.Canceling the call to the defenseXSS function has a significant impact on performance; The defenseXSS method is provided as a tool method;</p>
<p>5.Remove the logic of removing nodes with ql cursor class names from rich text content, and fix the issue of ineffective addition of empty lines when text breaks;</p>
<p>6.Remove the logic of delayed node editing when inserting new nodes;</p>
<p>7.Support direct editing of mathematical formulas in rich text editing boxes;</p>
<p>8.Add demonstration plugins to the packaged file;</p>
</blockquote>
<p>Demo</p>
<blockquote>
<p>1.支持配置水印显示在节点下方</p>
<p>2.导入存在多个画布的xmind文件支持选择指定的画布进行导入</p>
<p>3.优化富文本工具条下拉选项列表高度问题</p>
<p>4.新建和打开按钮增加导出的提示防止内容丢失</p>
<p>5.快捷键提示支持区分windows和mac</p>
</blockquote>
<h2>0.9.12</h2>
<p>Fix:</p>
<blockquote>

View File

@@ -22,8 +22,10 @@ const mindMap = new MindMap({
## Instantiation options
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ | -------- |
### 1.Base
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| el | Element | | Container element, must be a DOM elementWhen the position of container elements on the page has changed but the size has not changed, the 'getElRectInfo()' method must be called to update the relevant information inside the library; When the size also changes, the 'resize()' method must be called, otherwise it will cause some functional exceptions | Yes |
| data | Object 、null | | Mind map data, Please refer to the introduction of 【Data structure】 below. V0.9.9+supports passing empty objects or null, and the canvas will display blank space | |
| layout | String | logicalStructure | Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timelinev0.5.4+, timeline、timeline2v0.5.4+, up down alternating timeline、fishbonev0.5.4+, fishbone diagram | |
@@ -32,15 +34,10 @@ const mindMap = new MindMap({
| themeConfig | Object | {} | Theme configuration, will be merged with the selected theme, available fields refer to: [default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
| scaleRatio | Number | 0.1 | The incremental scaling ratio | |
| maxTag | Number | 5 | The maximum number of tags displayed in the node, any additional tags will be discarded | |
| exportPadding | Number | 20 | The padding for exporting images | |
| imgTextMargin | Number | 5 | The spacing between the image and text in the node | |
| textContentMargin | Number | 2 | The spacing between various text information in the node, such as the spacing between the icon and text | |
| selectTranslateStep | Number | 3 | The canvas offset when mouse moves to the edge during multi-select node | |
| selectTranslateLimit | Number | 20 | The distance from the edge when the canvas begins to offset during multi-select node | |
| customNoteContentShowv0.1.6+ | Object | null | Custom node note content display, object type, structure: {show: (noteContent, left, top, node) => {// your display node note logic. node is a new parameter added in v0.8.1+ version, representing node instances }, hide: () => {// your hide node note logic }} | |
| readonlyv0.1.7+ | Boolean | false | Whether it is read-only mode | |
| enableFreeDragv0.2.4+ | Boolean | false | Enable node free(Free drag means that nodes can be dragged to any position on the canvas. Please note that it is not a function of dragging nodes to become siblings of other nodes. The connection of free drag may have certain problems, so it is best not to use this feature) drag | |
| watermarkConfigv0.2.4+ | Object | | Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration | |
| textAutoWrapWidthv0.3.4+ | Number | 500 | Each line of text in the node will wrap automatically when it reaches the width | |
| customHandleMousewheelv0.4.3+ | Function | null | User-defined mouse wheel event processing can pass a function, and the callback parameter is the event object | |
| mousewheelActionv0.4.3+ | String | zoomv0.9.1+ default is move | The behavior of the mouse wheel, `zoom`(Zoom in and out)、`move`(Move up and down). If `customHandleMousewheel` passes a custom function, this property will not take effect | |
@@ -56,8 +53,6 @@ const mindMap = new MindMap({
| enableNodeTransitionMovev0.5.1+v0.6.7+ is remove this feature | Boolean | true | Whether to enable node animation transition | |
| nodeTransitionMoveDurationv0.5.1+v0.6.7+ is remove this feature | Number | 300 | If node animation transition is enabled, the transition time can be set using this attribute, in milliseconds | |
| initRootNodePositionv0.5.3+ | Array | null | The position of the initial root node can be passed as an array, default is `['center', 'center']`, Represents the root node at the center of the canvas, In addition to `center`, keywords can also be set to `left`, `top`, `right`, and `bottom`, In addition to passing keywords, each item in the array can also pass a number representing a specific pixel, Can pass a percentage string, such as `['40%', '60%']`, Represents a horizontal position at `40%` of the canvas width, and a vertical position at `60%` of the canvas height | |
| exportPaddingXv0.5.5+ | Number | 10 | Horizontal padding of graphics when exporting PNG, SVG, and PDF | |
| exportPaddingYv0.5.5+ | Number | 10 | Vertical padding of graphics when exporting PNG, SVG, and PDF | |
| nodeTextEditZIndexv0.5.5+ | Number | 3000 | | z-index of node text edit box elements |
| nodeNoteTooltipZIndexv0.5.5+ | Number | 3000 | z-index of floating layer elements in node comments | |
| isEndNodeTextEditOnClickOuterv0.5.5+ | Boolean | true | Whether to end the editing status of node text when clicking on an area outside the canvas | |
@@ -65,7 +60,6 @@ const mindMap = new MindMap({
| alwaysShowExpandBtnv0.5.8+ | Boolean | false | Whether to always display the expand and collapse buttons of nodes, which are only displayed when the mouse is moved up and activated by default | |
| iconListv0.5.8+ | Array | [] | The icons that can be inserted into the extension node, and each item in the array is an object. Please refer to the "Icon Configuration" table below for the detailed structure of the object | |
| maxNodeCacheCountv0.5.10+ | Number | 1000 | The maximum number of cached nodes. To optimize performance, an internal node cache pool is maintained to reuse nodes. This attribute allows you to specify the maximum number of caches in the pool | |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | Association Line Default Text | |
| fitPaddingv0.6.0+ | Number | 50 | The padding of mind mapping when adapting to canvas size, Unit: px | |
| enableCtrlKeyNodeSelectionv0.6.0+ | Boolean | true | Whether to enable the function of holding down the Ctrl key to select multiple nodes | |
| useLeftKeySelectionRightKeyDragv0.6.0+ | Boolean | false | Setting to left click to select multiple nodes and right click to drag the canvas. | |
@@ -74,56 +68,36 @@ const mindMap = new MindMap({
| customCreateNodeContentv0.6.3+ | Function/null | null | If `isUseCustomNodeContent` is set to `true`, then this option needs to be used to pass in a method that receives the node instance `node` as a parameter (if you want to obtain data for that node, you can use `node.nodeData.data`). You need to return the custom node content element, which is the DOM node. If a node does not require customization, you can return `null` | |
| mouseScaleCenterUseMousePositionv0.6.4-fix.1+ | Boolean | true | Is the mouse zoom centered around the current position of the mouse, otherwise centered around the canvas | |
| customInnerElsAppendTov0.6.12+ | null/HTMLElement | null | Specify the location where some internal elements (node text editing element, node note display element, associated line text editing element, node image adjustment button element) are added, and default to document.body | |
| nodeDragPlaceholderMaxSizev0.6.12+ | Number | 20 | When dragging an element, the maximum height of the block indicating the new position of the element | |
| enableCreateHiddenInputv0.6.13+v0.6.14+ remove this feature | Boolean | true | Is it allowed to create a hidden input box that will be focused when the node is activated for pasting data and automatically entering the text editing state | |
| enableAutoEnterTextEditWhenKeydownv0.6.13+ | Boolean | true | Does it automatically enter text editing mode when pressing the Chinese, English, or numeric buttons when there is an activation node?| |
| richTextEditFakeInPlacev0.6.13+ | Boolean | false | Set the rich text node edit box to match the size of the node, creating a pseudo in place editing effect. It should be noted that only when there is only text within the node and the shape is rectangular, can the effect be better | |
| customHandleClipboardTextv0.6.14+ | Function | null | Customize the processing of clipboard text. When pressing ctrl+v to paste, it will read the text and images from the user's clipboard. By default, it will only determine whether the text is regular text and node data in simple mind map format. If you want to process data from other mind maps, such as process, zhixi, etc., you can pass a function that takes the text from the current clipboard as a parameter and returns the processed data, which can be of two types: 1.If a pure text is returned, a child node will be directly created with that text; 2.Returns a node object in the following format: { simpleMindMap: true, data: { data: { text: '' }, children: [] } }, The representative is data in simple bind map format, and the node data is in the same format as the simple bind map node data. If your processing logic has asynchronous logic, you can also return a promise | |
| errorHandlerv0.6.15+ | Function | | Custom error handling functions currently only throw some asynchronous logic errors. Can pass a function that takes two parameters, the first being the wrong type and the second being the wrong object | |
| disableMouseWheelZoomv0.6.15+ | Boolean | false | Prohibit mouse wheel scaling, you can still use the API for scaling | |
| resetCssv0.6.16+ | String | * { margin: 0; padding: 0; box-sizing: border-box; } | When exporting images and SVGs, the default style overlay for rich text node content, which is embedded in HTML nodes in SVGs, will occur. If not overlaid, the node content will be offset | |
| enableDblclickResetv0.6.17+(v0.8.0+this attribute has been deleted) | Boolean | true(v0.7.0+changed to false) | Turn on the mouse and double-click to reset the position and zoom of the mind map | |
| enableDblclickBackToRootNodev0.8.0+ | Boolean | false | Whether to return to the root node when double clicking with the mouse, that is, to center the display of the root node | |
| minExportImgCanvasScalev0.7.0+ | Number | 2 | The scaling factor of canvas when exporting images and PDFs, which is set to the maximum value of window.devicePixelRatio to improve image clarity | |
| hoverRectColorv0.7.0+ | String | rgb(94, 200, 248) | The node mouse hover and the rectangular border color displayed when activated will add a transparency of 0.6 when hovering | |
| hoverRectPaddingv0.7.0+ | Number | 2 | The distance between the node mouse hover and the displayed rectangular border when activated and the node content | |
| selectTextOnEnterEditTextv0.7.0+ | Boolean | true | Is the text selected by default when double-clicking a node to enter node text editing? By default, it will only be selected when creating a new node | |
| deleteNodeActivev0.7.1+ | Boolean | true | Enable the function of automatically activating adjacent nodes or parent nodes after deleting nodes | |
| autoMoveWhenMouseInEdgeOnDragv0.7.1+ | Boolean | true | Whether to enable automatic canvas movement when the mouse moves to the edge of the canvas while dragging nodes | |
| fitv0.7.1-fix.2+ | Boolean | false | Is the first rendering scaled to fit the canvas size | |
| dragMultiNodeRectConfigv0.7.2+ | Object | { width: 40, height: 20, fill: '' } | The style configuration of the schematic rectangle that moves with the mouse when dragging multiple nodes, passing an object, and the field meanings are the width, height, and fill color of the rectangle | |
| dragPlaceholderRectFillv0.7.2+ | String | | The filling color of the schematic rectangle for the new position when dragging nodes. If not transmitted, the default color for the connected line is used | |
| dragOpacityConfigv0.7.2+ | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node | |
| tagsColorMapv0.7.2+ | Object | {} | The color of a custom node label can be transferred to an object, where key is the label content to be assigned a color, and value is the color of the label content. If not transferred internally, a corresponding color will be generated based on the label content | |
| cooperateStylev0.7.3+ | Object | { avatarSize: 22, fontSize: 12 } | The configuration of personnel avatar style during node collaboration editing, with field meanings as follows: avatar size, and if it is a text avatar, the size of the text | |
| associativeLineIsAlwaysAboveNodev0.8.0+ | Boolean | true | Is the associated line always displayed above the node? If set to false, it will be at the top level when creating and activating the associated line, and in other cases, it will be below the node | |
| onlyOneEnableActiveNodeOnCooperatev0.9.8+ | Boolean | false | During collaborative editing, the same node cannot be selected by multiple people at the same time | |
| defaultGeneralizationTextv0.8.0+ | String | 概要 | Insert default text for summary | |
| handleIsSplitByWrapOnPasteCreateNewNodev0.8.0+ | Function / null | null | When creating a new node by pasting text, control whether to automatically split the nodes based on line breaks. If there is a line break, multiple nodes will be created based on the line break. Otherwise, only one node will be created, and a function can be passed to return promise. resolve represents splitting based on line breaks, and reject represents ignoring line breaks | |
| addHistoryTimev0.8.0+ | Number | 100 | Only one historical record can be added within the specified time to avoid adding unnecessary intermediate states. Unit: ms | |
| isDisableDragv0.8.1+ | Boolean | false | Is disable dragging the canvas | |
| disableTouchZoomv0.8.1+ | Boolean | false | Prohibit double finger scaling, you can still use the API for scaling, which takes effect on the TouchEvent plugin | |
| highlightNodeBoxStylev0.9.0+ | Object | { stroke: 'rgb(94, 200, 248)', fill: 'transparent' } | Highlight box style when the mouse moves into the summary to highlight the node it belongs to | |
| createNewNodeBehaviorv0.9.1+ | String | default | Behavior when creating a new node. defaultBy default, newly created nodes will be activated and enter editing mode. If multiple new nodes are created simultaneously, they will only be activated and will not enter editing mode、notActiveDo not activate newly created nodes、activeOnlyOnly activate newly created nodes and do not enter editing mode | |
| defaultNodeImagev0.9.1-fix.2+ | String | | Image address, the default image displayed when node image loading fails | |
| handleNodePasteImgv0.9.2+ | null or Function | null | The processing method for pasting images from the clipboard on a node is to convert them into data:URL data and insert them into the node by default. You can use this method to upload image data to the server and save the URL of the image. An asynchronous method can be passed to receive image data of Blob type, and the specified structure needs to be returned: { url, size: {width, height} } | |
| isLimitMindMapInCanvasv0.9.2+ | Boolean | false | Whether to limit the mind map within the canvas. For example, when dragging to the right, the leftmost part of the mind map graphic will not be able to continue dragging to the right when it reaches the center of the canvas, and the same applies to other things | |
| isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+ | Boolean | true | When registering the Scrollbar plugin, will the mind map be limited to the canvas and the isLimitMindMapInCanvas configuration no longer work | |
| associativeLineInitPointsPositionv0.9.5+ | null / { from, to } | { from: '', to: '' } | By default, the position of the two endpoints of a newly created association line is calculated based on the relative position of the center points of the two nodes. If you want to fix the position, you can configure it through this option. If neither from nor to is transmitted, they will be automatically calculated. If only one is transmitted, the other will be automatically calculated. from and to optional values
left、top、bottom、right | |
| enableAdjustAssociativeLinePointsv0.9.5+ | Boolean | true | Is it allowed to adjust the position of the two endpoints of the associated line | |
| isOnlySearchCurrentRenderNodesv0.9.8+ | Boolean | false | Is it necessary to only search for the current rendered node, and nodes that have been collapsed will not be searched for | |
| onlyOneEnableActiveNodeOnCooperatev0.9.8+ | Boolean | false | During collaborative editing, the same node cannot be selected by multiple people at the same time | |
| beforeCooperateUpdatev0.9.8+ | Function、null | null | During collaborative editing, node operations are about to be updated to the lifecycle functions of other clients. The function takes an object as a parameter:{ type: 【createOrUpdateCreate or update nodes、deleteDelete node】, list: 【Array type, 1.When type=createOrUpdate, it represents the node data that has been created or updated, which will be synchronized to other clients, so you can modify the data; 2.When type=delete, represents the deleted node data】 } | |
| beforeShortcutRunv0.9.9+ | Function、null | null | The lifecycle function before the shortcut operation is about to be executed, returning true can prevent the operation from executing. The function takes two parameters: keyShortcut key、activeNodeListList of currently activated nodes | |
| rainbowLinesConfigv0.9.9+ | Object | { open: false, colorsList: [] } | Rainbow line configuration requires registering the RainbowLines plugin first. Object type, Structure: { open: false【Is turn on rainbow lines】, colorsList: []【Customize the color list for rainbow lines. If not set, the default color list will be used】 } | |
| addContentToHeaderv0.9.9+ | Function、null | null | Add custom content to the header when exporting PNG, SVG, and PDF. Can pass a function that can return null to indicate no content is added, or it can return an object, For a detailed introduction, please refer to section 【How to add custom content when exporting】 below | |
| addContentToFooterv0.9.9+ | Function、null | null | The basic definition is the same as addContentToHeader, adding custom content at the end | |
| demonstrateConfigv0.9.11+ | Object、null | null | Demonstration plugin configuration. If not transmitted, the default configuration will be used. An object can be transmitted. If only a certain property is configured, only that property can be set. Other properties that have not been set will also use the default configuration. For complete configuration, please refer to the 【Demonstration Plugin Configuration】 section below | |
| resetScaleOnMoveNodeToCenterv0.9.12+ | Boolean | false | Whether to reset the scaling level to 100% when moving nodes to the canvas center, returning to the root node, and other operationsThe underlying impact is on the moveNodeToCenter method of the render class | |
| createNodePrefixContentv0.9.12+ | Function、null | null | Add additional node pre content.Pre content refers to the pre content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, returns a DOM node, or returns null | |
| createNodePostfixContentv0.9.12+ | Function、null | null | Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, returns a DOM node, or returns null | |
| createNodePrefixContentv0.9.12+ | Function、null | null | Add additional node pre content.Pre content refers to the pre content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, Can return objects in {el, width, height} format, el is a DOM node object, width and height represent the width, height, and numerical type of the content. If custom content is not required, null can also be returned | |
| createNodePostfixContentv0.9.12+ | Function、null | null | Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section. The usage is the same as createNodePrefixContent | |
### Data structure
### 1.1Data structure
The basic data structure is as follows:
@@ -166,18 +140,7 @@ The basic data structure is as follows:
If you want to add custom fields, you can add them to the same level as 'data' and 'children'. If you want to add them to the 'data' object, please use the `_` Name your custom field at the beginning, and it will be used internally to determine whether it is a custom field.
### Watermark config
| Field Name | Type | Default Value | Description |
| ----------- | ------ | ------------------------------------------- | ------------------------------------------------------------ |
| text | String | '' | Watermark text. If it is an empty string, the watermark will not be displayed |
| lineSpacing | Number | 100 | Spacing between watermark lines |
| textSpacing | Number | 100 | Spacing between watermarks in the same row |
| angle | Number | 30 | Tilt angle of watermark, range: [0, 90] |
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | Watermark text style |
| onlyExportv0.9.2+ | Boolean | false | Is only add watermarks during export |
### Icon Configuration
### 1.2Icon Configuration
| Field Name | Type | Default Value | Description |
| ----------- | ------ | ------------------------------------------- | ------------------------------------------------------------ |
@@ -185,7 +148,19 @@ If you want to add custom fields, you can add them to the same level as 'data' a
| type | String | | Values for icon grouping |
| list | Array | | A list of icons under grouping, with each item in the array being an object, `{ name: '', icon: '' }``name`represents the name of the icon, `icon`represents the icon, Can be an `svg` icon, such as `<svg ...><path></path></svg>`, also can be a image `url`, or `base64` icon, such as `data:image/png;base64,...` |
### How to add custom content when exporting
### 2.Export plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| exportPadding | Number | 20 | The padding for exporting images | |
| exportPaddingXv0.5.5+ | Number | 10 | Horizontal padding of graphics when exporting PNG, SVG, and PDF | |
| exportPaddingYv0.5.5+ | Number | 10 | Vertical padding of graphics when exporting PNG, SVG, and PDF | |
| resetCssv0.6.16+ | String | * { margin: 0; padding: 0; box-sizing: border-box; } | When exporting images and SVGs, the default style overlay for rich text node content, which is embedded in HTML nodes in SVGs, will occur. If not overlaid, the node content will be offset | |
| minExportImgCanvasScalev0.7.0+ | Number | 2 | The scaling factor of canvas when exporting images and PDFs, which is set to the maximum value of window.devicePixelRatio to improve image clarity | |
| addContentToHeaderv0.9.9+ | Function、null | null | Add custom content to the header when exporting PNG, SVG, and PDF. Can pass a function that can return null to indicate no content is added, or it can return an object, For a detailed introduction, please refer to section 【How to add custom content when exporting】 below | |
| addContentToFooterv0.9.9+ | Function、null | null | The basic definition is the same as addContentToHeader, adding custom content at the end | |
#### 2.1How to add custom content when exporting
The two instantiation options `addContentToHeader` and `addContentToFooter` can be used to add custom content at the beginning and end when exporting `png``svg``pdf`, The default value is `null`, which means no configuration. A function can be passed and can return `null`, which means no content will be added. If you want to add content, you need to return the following structure:
@@ -220,7 +195,99 @@ new MindMap({
})
```
### Demonstration Plugin Configuration
### 3.Select plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| selectTranslateStep | Number | 3 | The canvas offset when mouse moves to the edge during multi-select node | |
| selectTranslateLimit | Number | 20 | The distance from the edge when the canvas begins to offset during multi-select node | |
### 4.Drag plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| enableFreeDragv0.2.4+ | Boolean | false | Enable node free(Free drag means that nodes can be dragged to any position on the canvas. Please note that it is not a function of dragging nodes to become siblings of other nodes. The connection of free drag may have certain problems, so it is best not to use this feature) drag | |
| nodeDragPlaceholderMaxSizev0.6.12+v0.10.0+ has been abolished | Number | 20 | When dragging an element, the maximum height of the block indicating the new position of the element | |
| autoMoveWhenMouseInEdgeOnDragv0.7.1+ | Boolean | true | Whether to enable automatic canvas movement when the mouse moves to the edge of the canvas while dragging nodes | |
| dragMultiNodeRectConfigv0.7.2+ | Object | { width: 40, height: 20, fill: 'rgb(94, 200, 248)' } | The style configuration of the schematic rectangle that moves with the mouse when dragging multiple nodes, passing an object, and the field meanings are the width, height, and fill color of the rectangle | |
| dragPlaceholderRectFillv0.7.2+ | String | rgb(94, 200, 248) | The filling color of the schematic rectangle for the new position when dragging nodes. | |
| dragPlaceholderLineConfigv0.10.0+ | Object | { color: 'rgb(94, 200, 248)', width: 2 } | Style configuration of schematic lines for new positions when dragging nodes | |
| dragOpacityConfigv0.7.2+ | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node | |
### 5.Watermark plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| watermarkConfigv0.2.4+ | Object | | Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration | |
#### 5.1Watermark config
| Field Name | Type | Default Value | Description |
| ----------- | ------ | ------------------------------------------- | ------------------------------------------------------------ |
| text | String | '' | Watermark text. If it is an empty string, the watermark will not be displayed |
| lineSpacing | Number | 100 | Spacing between watermark lines |
| textSpacing | Number | 100 | Spacing between watermarks in the same row |
| angle | Number | 30 | Tilt angle of watermark, range: [0, 90] |
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | Watermark text style |
| onlyExportv0.9.2+ | Boolean | false | Is only add watermarks during export |
| belowNodev0.10.0+ | Boolean | false | Is the watermark displayed below the node |
### 6.AssociativeLine plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | Association Line Default Text | |
| associativeLineIsAlwaysAboveNodev0.8.0+ | Boolean | true | Is the associated line always displayed above the node? If set to false, it will be at the top level when creating and activating the associated line, and in other cases, it will be below the node | |
| associativeLineInitPointsPositionv0.9.5+ | null / { from, to } | { from: '', to: '' } | By default, the position of the two endpoints of a newly created association line is calculated based on the relative position of the center points of the two nodes. If you want to fix the position, you can configure it through this option. If neither from nor to is transmitted, they will be automatically calculated. If only one is transmitted, the other will be automatically calculated. from and to optional values
left、top、bottom、right | |
| enableAdjustAssociativeLinePointsv0.9.5+ | Boolean | true | Is it allowed to adjust the position of the two endpoints of the associated line | |
### 7.RichText plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| richTextEditFakeInPlacev0.6.13+ | Boolean | false | Set the rich text node edit box to match the size of the node, creating a pseudo in place editing effect. It should be noted that only when there is only text within the node and the shape is rectangular, can the effect be better | |
| enableEditFormulaInRichTextEditv0.10.0+ | Boolean | true | | Whether to enable direct editing of mathematical formulas in rich text editing boxes |
| transformRichTextOnEnterEditv0.10.0+ | null、Function | null | To convert rich text content, you can pass a function that will be called when entering rich text editing. The function receives the rich text content that is about to be edited and needs to return the processed rich text content | |
| beforeHideRichTextEditv0.10.0+ | null、Function | null | You can pass a function that will be executed before the end of rich text editing. The function receives a richText instance, so you can update the kill document data at this time | |
### 8.TouchEvent plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| disableTouchZoomv0.8.1+ | Boolean | false | Prohibit double finger scaling, you can still use the API for scaling, which takes effect on the TouchEvent plugin | |
### 9.Scrollbar plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+ | Boolean | true | When registering the Scrollbar plugin, will the mind map be limited to the canvas and the isLimitMindMapInCanvas configuration no longer work | |
### 10.Search plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| isOnlySearchCurrentRenderNodesv0.9.8+ | Boolean | false | Is it necessary to only search for the current rendered node, and nodes that have been collapsed will not be searched for | |
### 11.Cooperate plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| beforeCooperateUpdatev0.9.8+ | Function、null | null | During collaborative editing, node operations are about to be updated to the lifecycle functions of other clients. The function takes an object as a parameter:{ type: 【createOrUpdateCreate or update nodes、deleteDelete node】, list: 【Array type, 1.When type=createOrUpdate, it represents the node data that has been created or updated, which will be synchronized to other clients, so you can modify the data; 2.When type=delete, represents the deleted node data】 } | |
### 12.RainbowLines plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| rainbowLinesConfigv0.9.9+ | Object | { open: false, colorsList: [] } | Rainbow line configuration requires registering the RainbowLines plugin first. Object type, Structure: { open: false【Is turn on rainbow lines】, colorsList: []【Customize the color list for rainbow lines. If not set, the default color list will be used】 } | |
### 13.Demonstrate plugin
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
| demonstrateConfigv0.9.11+ | Object、null | null | Demonstration plugin configuration. If not transmitted, the default configuration will be used. An object can be transmitted. If only a certain property is configured, only that property can be set. Other properties that have not been set will also use the default configuration. For complete configuration, please refer to the 【Demonstration Plugin Configuration】 section below | |
#### 13.1Demonstration Plugin Configuration
| Field Name | Type | Default Value | Description |
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
@@ -486,7 +553,8 @@ Listen to an event. Event list:
| node_img_mouseenterv0.6.5+ | Node image mouseenter event | thisnode instance、imgNodeimg node、eevent object |
| node_img_mouseleavev0.6.5+ | Node image mouseleave event | thisnode instance、imgNodeimg node、eevent object |
| node_img_mousemovev0.6.5+ | Node image mousemove event | thisnode instance、imgNodeimg node、eevent object |
| node_tree_render_endv0.2.16+ | Node tree render end event | |
| node_tree_render_endv0.2.16+ | Node tree render end event | |
| node_tree_render_startv0.10.0+ | Node tree start rendering event | |
| rich_text_selection_changev0.4.0+ | Available when the `RichText` plugin is registered. Triggered when the text selection area changes when the node is edited | hasRangeWhether there is a selection、rectInfoSize and location information of the selected area、formatInfoText formatting information of the selected area |
| transforming-dom-to-imagesv0.4.0+ | Available when the `RichText` plugin is registered. When there is a `DOM` node in `svg`, the `DOM` node will be converted to an image when exporting to an image. This event will be triggered during the conversion process. You can use this event to prompt the user about the node to which you are currently converting | indexIndex of the node currently converted to、lenTotal number of nodes to be converted |
| node_draggingv0.4.5+ | Triggered when a node is dragged | node(The currently dragged node) |

View File

@@ -17,6 +17,7 @@
});
</code></pre>
<h2>Instantiation options</h2>
<h3>1.Base</h3>
<table>
<thead>
<tr>
@@ -85,13 +86,6 @@
<td></td>
</tr>
<tr>
<td>exportPadding</td>
<td>Number</td>
<td>20</td>
<td>The padding for exporting images</td>
<td></td>
</tr>
<tr>
<td>imgTextMargin</td>
<td>Number</td>
<td>5</td>
@@ -106,20 +100,6 @@
<td></td>
</tr>
<tr>
<td>selectTranslateStep</td>
<td>Number</td>
<td>3</td>
<td>The canvas offset when mouse moves to the edge during multi-select node</td>
<td></td>
</tr>
<tr>
<td>selectTranslateLimit</td>
<td>Number</td>
<td>20</td>
<td>The distance from the edge when the canvas begins to offset during multi-select node</td>
<td></td>
</tr>
<tr>
<td>customNoteContentShowv0.1.6+</td>
<td>Object</td>
<td>null</td>
@@ -134,20 +114,6 @@
<td></td>
</tr>
<tr>
<td>enableFreeDragv0.2.4+</td>
<td>Boolean</td>
<td>false</td>
<td>Enable node free(Free drag means that nodes can be dragged to any position on the canvas. Please note that it is not a function of dragging nodes to become siblings of other nodes. The connection of free drag may have certain problems, so it is best not to use this feature) drag</td>
<td></td>
</tr>
<tr>
<td>watermarkConfigv0.2.4+</td>
<td>Object</td>
<td></td>
<td>Watermark config, Please refer to the table Watermark config below for detailed configuration</td>
<td></td>
</tr>
<tr>
<td>textAutoWrapWidthv0.3.4+</td>
<td>Number</td>
<td>500</td>
@@ -253,20 +219,6 @@
<td></td>
</tr>
<tr>
<td>exportPaddingXv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>Horizontal padding of graphics when exporting PNG, SVG, and PDF</td>
<td></td>
</tr>
<tr>
<td>exportPaddingYv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>Vertical padding of graphics when exporting PNG, SVG, and PDF</td>
<td></td>
</tr>
<tr>
<td>nodeTextEditZIndexv0.5.5+</td>
<td>Number</td>
<td>3000</td>
@@ -316,13 +268,6 @@
<td></td>
</tr>
<tr>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td>关联</td>
<td>Association Line Default Text</td>
<td></td>
</tr>
<tr>
<td>fitPaddingv0.6.0+</td>
<td>Number</td>
<td>50</td>
@@ -379,13 +324,6 @@
<td></td>
</tr>
<tr>
<td>nodeDragPlaceholderMaxSizev0.6.12+</td>
<td>Number</td>
<td>20</td>
<td>When dragging an element, the maximum height of the block indicating the new position of the element</td>
<td></td>
</tr>
<tr>
<td>enableCreateHiddenInputv0.6.13+v0.6.14+ remove this feature</td>
<td>Boolean</td>
<td>true</td>
@@ -400,13 +338,6 @@
<td></td>
</tr>
<tr>
<td>richTextEditFakeInPlacev0.6.13+</td>
<td>Boolean</td>
<td>false</td>
<td>Set the rich text node edit box to match the size of the node, creating a pseudo in place editing effect. It should be noted that only when there is only text within the node and the shape is rectangular, can the effect be better</td>
<td></td>
</tr>
<tr>
<td>customHandleClipboardTextv0.6.14+</td>
<td>Function</td>
<td>null</td>
@@ -428,13 +359,6 @@
<td></td>
</tr>
<tr>
<td>resetCssv0.6.16+</td>
<td>String</td>
<td>* { margin: 0; padding: 0; box-sizing: border-box; }</td>
<td>When exporting images and SVGs, the default style overlay for rich text node content, which is embedded in HTML nodes in SVGs, will occur. If not overlaid, the node content will be offset</td>
<td></td>
</tr>
<tr>
<td>enableDblclickResetv0.6.17+(v0.8.0+this attribute has been deleted)</td>
<td>Boolean</td>
<td>true(v0.7.0+changed to false)</td>
@@ -449,13 +373,6 @@
<td></td>
</tr>
<tr>
<td>minExportImgCanvasScalev0.7.0+</td>
<td>Number</td>
<td>2</td>
<td>The scaling factor of canvas when exporting images and PDFs, which is set to the maximum value of window.devicePixelRatio to improve image clarity</td>
<td></td>
</tr>
<tr>
<td>hoverRectColorv0.7.0+</td>
<td>String</td>
<td>rgb(94, 200, 248)</td>
@@ -484,13 +401,6 @@
<td></td>
</tr>
<tr>
<td>autoMoveWhenMouseInEdgeOnDragv0.7.1+</td>
<td>Boolean</td>
<td>true</td>
<td>Whether to enable automatic canvas movement when the mouse moves to the edge of the canvas while dragging nodes</td>
<td></td>
</tr>
<tr>
<td>fitv0.7.1-fix.2+</td>
<td>Boolean</td>
<td>false</td>
@@ -498,27 +408,6 @@
<td></td>
</tr>
<tr>
<td>dragMultiNodeRectConfigv0.7.2+</td>
<td>Object</td>
<td>{ width: 40, height: 20, fill: '' }</td>
<td>The style configuration of the schematic rectangle that moves with the mouse when dragging multiple nodes, passing an object, and the field meanings are the width, height, and fill color of the rectangle</td>
<td></td>
</tr>
<tr>
<td>dragPlaceholderRectFillv0.7.2+</td>
<td>String</td>
<td></td>
<td>The filling color of the schematic rectangle for the new position when dragging nodes. If not transmitted, the default color for the connected line is used</td>
<td></td>
</tr>
<tr>
<td>dragOpacityConfigv0.7.2+</td>
<td>Object</td>
<td>{ cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 }</td>
<td>The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node</td>
<td></td>
</tr>
<tr>
<td>tagsColorMapv0.7.2+</td>
<td>Object</td>
<td>{}</td>
@@ -533,10 +422,10 @@
<td></td>
</tr>
<tr>
<td>associativeLineIsAlwaysAboveNodev0.8.0+</td>
<td>onlyOneEnableActiveNodeOnCooperatev0.9.8+</td>
<td>Boolean</td>
<td>true</td>
<td>Is the associated line always displayed above the node? If set to false, it will be at the top level when creating and activating the associated line, and in other cases, it will be below the node</td>
<td>false</td>
<td>During collaborative editing, the same node cannot be selected by multiple people at the same time</td>
<td></td>
</tr>
<tr>
@@ -568,13 +457,6 @@
<td></td>
</tr>
<tr>
<td>disableTouchZoomv0.8.1+</td>
<td>Boolean</td>
<td>false</td>
<td>Prohibit double finger scaling, you can still use the API for scaling, which takes effect on the TouchEvent plugin</td>
<td></td>
</tr>
<tr>
<td>highlightNodeBoxStylev0.9.0+</td>
<td>Object</td>
<td>{ stroke: 'rgb(94, 200, 248)', fill: 'transparent' }</td>
@@ -610,55 +492,6 @@
<td></td>
</tr>
<tr>
<td>isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+</td>
<td>Boolean</td>
<td>true</td>
<td>When registering the Scrollbar plugin, will the mind map be limited to the canvas and the isLimitMindMapInCanvas configuration no longer work</td>
<td></td>
</tr>
<tr>
<td>associativeLineInitPointsPositionv0.9.5+</td>
<td>null / { from, to }</td>
<td>{ from: '', to: '' }</td>
<td>By default, the position of the two endpoints of a newly created association line is calculated based on the relative position of the center points of the two nodes. If you want to fix the position, you can configure it through this option. If neither from nor to is transmitted, they will be automatically calculated. If only one is transmitted, the other will be automatically calculated. from and to optional values</td>
<td></td>
</tr>
<tr>
<td>left、top、bottom、right</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>enableAdjustAssociativeLinePointsv0.9.5+</td>
<td>Boolean</td>
<td>true</td>
<td>Is it allowed to adjust the position of the two endpoints of the associated line</td>
<td></td>
</tr>
<tr>
<td>isOnlySearchCurrentRenderNodesv0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>Is it necessary to only search for the current rendered node, and nodes that have been collapsed will not be searched for</td>
<td></td>
</tr>
<tr>
<td>onlyOneEnableActiveNodeOnCooperatev0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>During collaborative editing, the same node cannot be selected by multiple people at the same time</td>
<td></td>
</tr>
<tr>
<td>beforeCooperateUpdatev0.9.8+</td>
<td>Function、null</td>
<td>null</td>
<td>During collaborative editing, node operations are about to be updated to the lifecycle functions of other clients. The function takes an object as a parameter:{ type: 【createOrUpdateCreate or update nodes、deleteDelete node】, list: 【Array type, 1.When type=createOrUpdate, it represents the node data that has been created or updated, which will be synchronized to other clients, so you can modify the data; 2.When type=delete, represents the deleted node data】 }</td>
<td></td>
</tr>
<tr>
<td>beforeShortcutRunv0.9.9+</td>
<td>Function、null</td>
<td>null</td>
@@ -666,34 +499,6 @@
<td></td>
</tr>
<tr>
<td>rainbowLinesConfigv0.9.9+</td>
<td>Object</td>
<td>{ open: false, colorsList: [] }</td>
<td>Rainbow line configuration requires registering the RainbowLines plugin first. Object type, Structure: { open: false【Is turn on rainbow lines】, colorsList: []【Customize the color list for rainbow lines. If not set, the default color list will be used】 }</td>
<td></td>
</tr>
<tr>
<td>addContentToHeaderv0.9.9+</td>
<td>Function、null</td>
<td>null</td>
<td>Add custom content to the header when exporting PNG, SVG, and PDF. Can pass a function that can return null to indicate no content is added, or it can return an object, For a detailed introduction, please refer to section 【How to add custom content when exporting】 below</td>
<td></td>
</tr>
<tr>
<td>addContentToFooterv0.9.9+</td>
<td>Function、null</td>
<td>null</td>
<td>The basic definition is the same as addContentToHeader, adding custom content at the end</td>
<td></td>
</tr>
<tr>
<td>demonstrateConfigv0.9.11+</td>
<td>Object、null</td>
<td>null</td>
<td>Demonstration plugin configuration. If not transmitted, the default configuration will be used. An object can be transmitted. If only a certain property is configured, only that property can be set. Other properties that have not been set will also use the default configuration. For complete configuration, please refer to the 【Demonstration Plugin Configuration】 section below</td>
<td></td>
</tr>
<tr>
<td>resetScaleOnMoveNodeToCenterv0.9.12+</td>
<td>Boolean</td>
<td>false</td>
@@ -704,19 +509,19 @@
<td>createNodePrefixContentv0.9.12+</td>
<td>Function、null</td>
<td>null</td>
<td>Add additional node pre content.Pre content refers to the pre content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, returns a DOM node, or returns null</td>
<td>Add additional node pre content.Pre content refers to the pre content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, Can return objects in {el, width, height} format, el is a DOM node object, width and height represent the width, height, and numerical type of the content. If custom content is not required, null can also be returned</td>
<td></td>
</tr>
<tr>
<td>createNodePostfixContentv0.9.12+</td>
<td>Function、null</td>
<td>null</td>
<td>Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, returns a DOM node, or returns null</td>
<td>Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section. The usage is the same as createNodePrefixContent</td>
<td></td>
</tr>
</tbody>
</table>
<h3>Data structure</h3>
<h3>1.1Data structure</h3>
<p>The basic data structure is as follows:</p>
<pre class="hljs"><code>{
<span class="hljs-attr">data</span>: {
@@ -754,7 +559,241 @@
}
</code></pre>
<p>If you want to add custom fields, you can add them to the same level as 'data' and 'children'. If you want to add them to the 'data' object, please use the <code>_</code> Name your custom field at the beginning, and it will be used internally to determine whether it is a custom field.</p>
<h3>Watermark config</h3>
<h3>1.2Icon Configuration</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td>
<td>String</td>
<td></td>
<td>The name of the icon group</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td></td>
<td>Values for icon grouping</td>
</tr>
<tr>
<td>list</td>
<td>Array</td>
<td></td>
<td>A list of icons under grouping, with each item in the array being an object, <code>{ name: '', icon: '' }</code><code>name</code>represents the name of the icon, <code>icon</code>represents the icon, Can be an <code>svg</code> icon, such as <code>&lt;svg ...&gt;&lt;path&gt;&lt;/path&gt;&lt;/svg&gt;</code>, also can be a image <code>url</code>, or <code>base64</code> icon, such as <code>data:image/png;base64,...</code></td>
</tr>
</tbody>
</table>
<h3>2.Export plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>exportPadding</td>
<td>Number</td>
<td>20</td>
<td>The padding for exporting images</td>
<td></td>
</tr>
<tr>
<td>exportPaddingXv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>Horizontal padding of graphics when exporting PNG, SVG, and PDF</td>
<td></td>
</tr>
<tr>
<td>exportPaddingYv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>Vertical padding of graphics when exporting PNG, SVG, and PDF</td>
<td></td>
</tr>
<tr>
<td>resetCssv0.6.16+</td>
<td>String</td>
<td>* { margin: 0; padding: 0; box-sizing: border-box; }</td>
<td>When exporting images and SVGs, the default style overlay for rich text node content, which is embedded in HTML nodes in SVGs, will occur. If not overlaid, the node content will be offset</td>
<td></td>
</tr>
<tr>
<td>minExportImgCanvasScalev0.7.0+</td>
<td>Number</td>
<td>2</td>
<td>The scaling factor of canvas when exporting images and PDFs, which is set to the maximum value of window.devicePixelRatio to improve image clarity</td>
<td></td>
</tr>
<tr>
<td>addContentToHeaderv0.9.9+</td>
<td>Function、null</td>
<td>null</td>
<td>Add custom content to the header when exporting PNG, SVG, and PDF. Can pass a function that can return null to indicate no content is added, or it can return an object, For a detailed introduction, please refer to section 【How to add custom content when exporting】 below</td>
<td></td>
</tr>
<tr>
<td>addContentToFooterv0.9.9+</td>
<td>Function、null</td>
<td>null</td>
<td>The basic definition is the same as addContentToHeader, adding custom content at the end</td>
<td></td>
</tr>
</tbody>
</table>
<h4>2.1How to add custom content when exporting</h4>
<p>The two instantiation options <code>addContentToHeader</code> and <code>addContentToFooter</code> can be used to add custom content at the beginning and end when exporting <code>png</code>、<code>svg</code>、<code>pdf</code>, The default value is <code>null</code>, which means no configuration. A function can be passed and can return <code>null</code>, which means no content will be added. If you want to add content, you need to return the following structure:</p>
<pre class="hljs"><code>{
el,// Custom DOM node to be added, styles can be inline
cssText,// Optional, if the style does not want to be inlined, you can pass this value as a CSS string
height: 50// The height of the returned DOM node must be passed
}
</code></pre>
<p>A simple example:</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-attr">addContentToFooter</span>: <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> el = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;div&#x27;</span>)
el.className = <span class="hljs-string">&#x27;footer&#x27;</span>
el.innerHTML = <span class="hljs-string">&#x27;From: simple-mind-map&#x27;</span>
<span class="hljs-keyword">const</span> cssText = <span class="hljs-string">`
.footer {
width: 100%;
height: 30px;
}
`</span>
<span class="hljs-keyword">return</span> {
el,
cssText,
<span class="hljs-attr">height</span>: <span class="hljs-number">30</span>
}
}
})
</code></pre>
<h3>3.Select plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>selectTranslateStep</td>
<td>Number</td>
<td>3</td>
<td>The canvas offset when mouse moves to the edge during multi-select node</td>
<td></td>
</tr>
<tr>
<td>selectTranslateLimit</td>
<td>Number</td>
<td>20</td>
<td>The distance from the edge when the canvas begins to offset during multi-select node</td>
<td></td>
</tr>
</tbody>
</table>
<h3>4.Drag plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>enableFreeDragv0.2.4+</td>
<td>Boolean</td>
<td>false</td>
<td>Enable node free(Free drag means that nodes can be dragged to any position on the canvas. Please note that it is not a function of dragging nodes to become siblings of other nodes. The connection of free drag may have certain problems, so it is best not to use this feature) drag</td>
<td></td>
</tr>
<tr>
<td>nodeDragPlaceholderMaxSizev0.6.12+v0.10.0+ has been abolished</td>
<td>Number</td>
<td>20</td>
<td>When dragging an element, the maximum height of the block indicating the new position of the element</td>
<td></td>
</tr>
<tr>
<td>autoMoveWhenMouseInEdgeOnDragv0.7.1+</td>
<td>Boolean</td>
<td>true</td>
<td>Whether to enable automatic canvas movement when the mouse moves to the edge of the canvas while dragging nodes</td>
<td></td>
</tr>
<tr>
<td>dragMultiNodeRectConfigv0.7.2+</td>
<td>Object</td>
<td>{ width: 40, height: 20, fill: 'rgb(94, 200, 248)' }</td>
<td>The style configuration of the schematic rectangle that moves with the mouse when dragging multiple nodes, passing an object, and the field meanings are the width, height, and fill color of the rectangle</td>
<td></td>
</tr>
<tr>
<td>dragPlaceholderRectFillv0.7.2+</td>
<td>String</td>
<td>rgb(94, 200, 248)</td>
<td>The filling color of the schematic rectangle for the new position when dragging nodes.</td>
<td></td>
</tr>
<tr>
<td>dragPlaceholderLineConfigv0.10.0+</td>
<td>Object</td>
<td>{ color: 'rgb(94, 200, 248)', width: 2 }</td>
<td>Style configuration of schematic lines for new positions when dragging nodes</td>
<td></td>
</tr>
<tr>
<td>dragOpacityConfigv0.7.2+</td>
<td>Object</td>
<td>{ cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 }</td>
<td>The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node</td>
<td></td>
</tr>
</tbody>
</table>
<h3>5.Watermark plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>watermarkConfigv0.2.4+</td>
<td>Object</td>
<td></td>
<td>Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration</td>
<td></td>
</tr>
</tbody>
</table>
<h4>5.1Watermark config</h4>
<table>
<thead>
<tr>
@@ -801,9 +840,15 @@
<td>false</td>
<td>Is only add watermarks during export</td>
</tr>
<tr>
<td>belowNodev0.10.0+</td>
<td>Boolean</td>
<td>false</td>
<td>Is the watermark displayed below the node</td>
</tr>
</tbody>
</table>
<h3>Icon Configuration</h3>
<h3>6.AssociativeLine plugin</h3>
<table>
<thead>
<tr>
@@ -811,58 +856,216 @@
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td>关联</td>
<td>Association Line Default Text</td>
<td></td>
<td>The name of the icon group</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td>associativeLineIsAlwaysAboveNodev0.8.0+</td>
<td>Boolean</td>
<td>true</td>
<td>Is the associated line always displayed above the node? If set to false, it will be at the top level when creating and activating the associated line, and in other cases, it will be below the node</td>
<td></td>
<td>Values for icon grouping</td>
</tr>
<tr>
<td>list</td>
<td>Array</td>
<td>associativeLineInitPointsPositionv0.9.5+</td>
<td>null / { from, to }</td>
<td>{ from: '', to: '' }</td>
<td>By default, the position of the two endpoints of a newly created association line is calculated based on the relative position of the center points of the two nodes. If you want to fix the position, you can configure it through this option. If neither from nor to is transmitted, they will be automatically calculated. If only one is transmitted, the other will be automatically calculated. from and to optional values</td>
<td></td>
</tr>
<tr>
<td>left、top、bottom、right</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>enableAdjustAssociativeLinePointsv0.9.5+</td>
<td>Boolean</td>
<td>true</td>
<td>Is it allowed to adjust the position of the two endpoints of the associated line</td>
<td></td>
<td>A list of icons under grouping, with each item in the array being an object, <code>{ name: '', icon: '' }</code><code>name</code>represents the name of the icon, <code>icon</code>represents the icon, Can be an <code>svg</code> icon, such as <code>&lt;svg ...&gt;&lt;path&gt;&lt;/path&gt;&lt;/svg&gt;</code>, also can be a image <code>url</code>, or <code>base64</code> icon, such as <code>data:image/png;base64,...</code></td>
</tr>
</tbody>
</table>
<h3>How to add custom content when exporting</h3>
<p>The two instantiation options <code>addContentToHeader</code> and <code>addContentToFooter</code> can be used to add custom content at the beginning and end when exporting <code>png</code>、<code>svg</code>、<code>pdf</code>, The default value is <code>null</code>, which means no configuration. A function can be passed and can return <code>null</code>, which means no content will be added. If you want to add content, you need to return the following structure:</p>
<pre class="hljs"><code>{
el,// Custom DOM node to be added, styles can be inline
cssText,// Optional, if the style does not want to be inlined, you can pass this value as a CSS string
height: 50// The height of the returned DOM node must be passed
}
</code></pre>
<p>A simple example:</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-attr">addContentToFooter</span>: <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> el = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;div&#x27;</span>)
el.className = <span class="hljs-string">&#x27;footer&#x27;</span>
el.innerHTML = <span class="hljs-string">&#x27;From: simple-mind-map&#x27;</span>
<span class="hljs-keyword">const</span> cssText = <span class="hljs-string">`
.footer {
width: 100%;
height: 30px;
}
`</span>
<span class="hljs-keyword">return</span> {
el,
cssText,
<span class="hljs-attr">height</span>: <span class="hljs-number">30</span>
}
}
})
</code></pre>
<h3>Demonstration Plugin Configuration</h3>
<h3>7.RichText plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>richTextEditFakeInPlacev0.6.13+</td>
<td>Boolean</td>
<td>false</td>
<td>Set the rich text node edit box to match the size of the node, creating a pseudo in place editing effect. It should be noted that only when there is only text within the node and the shape is rectangular, can the effect be better</td>
<td></td>
</tr>
<tr>
<td>enableEditFormulaInRichTextEditv0.10.0+</td>
<td>Boolean</td>
<td>true</td>
<td></td>
<td>Whether to enable direct editing of mathematical formulas in rich text editing boxes</td>
</tr>
<tr>
<td>transformRichTextOnEnterEditv0.10.0+</td>
<td>null、Function</td>
<td>null</td>
<td>To convert rich text content, you can pass a function that will be called when entering rich text editing. The function receives the rich text content that is about to be edited and needs to return the processed rich text content</td>
<td></td>
</tr>
<tr>
<td>beforeHideRichTextEditv0.10.0+</td>
<td>null、Function</td>
<td>null</td>
<td>You can pass a function that will be executed before the end of rich text editing. The function receives a richText instance, so you can update the kill document data at this time</td>
<td></td>
</tr>
</tbody>
</table>
<h3>8.TouchEvent plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>disableTouchZoomv0.8.1+</td>
<td>Boolean</td>
<td>false</td>
<td>Prohibit double finger scaling, you can still use the API for scaling, which takes effect on the TouchEvent plugin</td>
<td></td>
</tr>
</tbody>
</table>
<h3>9.Scrollbar plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+</td>
<td>Boolean</td>
<td>true</td>
<td>When registering the Scrollbar plugin, will the mind map be limited to the canvas and the isLimitMindMapInCanvas configuration no longer work</td>
<td></td>
</tr>
</tbody>
</table>
<h3>10.Search plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>isOnlySearchCurrentRenderNodesv0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>Is it necessary to only search for the current rendered node, and nodes that have been collapsed will not be searched for</td>
<td></td>
</tr>
</tbody>
</table>
<h3>11.Cooperate plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>beforeCooperateUpdatev0.9.8+</td>
<td>Function、null</td>
<td>null</td>
<td>During collaborative editing, node operations are about to be updated to the lifecycle functions of other clients. The function takes an object as a parameter:{ type: 【createOrUpdateCreate or update nodes、deleteDelete node】, list: 【Array type, 1.When type=createOrUpdate, it represents the node data that has been created or updated, which will be synchronized to other clients, so you can modify the data; 2.When type=delete, represents the deleted node data】 }</td>
<td></td>
</tr>
</tbody>
</table>
<h3>12.RainbowLines plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>rainbowLinesConfigv0.9.9+</td>
<td>Object</td>
<td>{ open: false, colorsList: [] }</td>
<td>Rainbow line configuration requires registering the RainbowLines plugin first. Object type, Structure: { open: false【Is turn on rainbow lines】, colorsList: []【Customize the color list for rainbow lines. If not set, the default color list will be used】 }</td>
<td></td>
</tr>
</tbody>
</table>
<h3>13.Demonstrate plugin</h3>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Default Value</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>demonstrateConfigv0.9.11+</td>
<td>Object、null</td>
<td>null</td>
<td>Demonstration plugin configuration. If not transmitted, the default configuration will be used. An object can be transmitted. If only a certain property is configured, only that property can be set. Other properties that have not been set will also use the default configuration. For complete configuration, please refer to the 【Demonstration Plugin Configuration】 section below</td>
<td></td>
</tr>
</tbody>
</table>
<h4>13.1Demonstration Plugin Configuration</h4>
<table>
<thead>
<tr>
@@ -1239,6 +1442,11 @@ poor performance and should be used sparingly.</p>
<td></td>
</tr>
<tr>
<td>node_tree_render_startv0.10.0+</td>
<td>Node tree start rendering event</td>
<td></td>
</tr>
<tr>
<td>rich_text_selection_changev0.4.0+</td>
<td>Available when the <code>RichText</code> plugin is registered. Triggered when the text selection area changes when the node is edited</td>
<td>hasRangeWhether there is a selection、rectInfoSize and location information of the selected area、formatInfoText formatting information of the selected area</td>

View File

@@ -384,7 +384,7 @@ Open source is not easy. If this project is helpful to you, you can invite the a
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/孟照星.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>孟照星</p>
<p>Alex</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/子豪.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
@@ -394,4 +394,20 @@ Open source is not easy. If this project is helpful to you, you can invite the a
<img src="../../../../assets/avatar/宏涛.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>宏涛</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/最多5个字.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>最多5个字</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/雨馨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>雨馨</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/ZX.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>ZX</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/峰.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>峰</p>
</div>
</div>

View File

@@ -8,18 +8,18 @@
</blockquote>
<h2>Features</h2>
<ul>
<li><input type="checkbox" id="checkbox252" checked="true" /><label for="checkbox252">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
<li><input type="checkbox" id="checkbox253" checked="true" /><label for="checkbox253">Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
<li><input type="checkbox" id="checkbox254" checked="true" /><label for="checkbox254">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
<li><input type="checkbox" id="checkbox255" checked="true" /><label for="checkbox255">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
<li><input type="checkbox" id="checkbox256" checked="true" /><label for="checkbox256">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, Support for expanding node content, and fully customize node content using DDM</label></li>
<li><input type="checkbox" id="checkbox257" checked="true" /><label for="checkbox257">Support canvas dragging and scaling</label></li>
<li><input type="checkbox" id="checkbox258" checked="true" /><label for="checkbox258">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
<li><input type="checkbox" id="checkbox259" checked="true" /><label for="checkbox259">Supoorts to export as </label><code>json</code><code>png</code><code>svg</code><code>pdf</code><code>markdown</code><code>xmind</code><code>txt</code>, support import from <code>json</code><code>xmind</code><code>markdown</code></li>
<li><input type="checkbox" id="checkbox260" checked="true" /><label for="checkbox260">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, scrollbar, Hand drawn style, and rainbow lines</label></li>
<li><input type="checkbox" id="checkbox261" checked="true" /><label for="checkbox261">Provide rich configurations to meet various scenarios and usage habits</label></li>
<li><input type="checkbox" id="checkbox262" checked="true" /><label for="checkbox262">Support collaborative editing</label></li>
<li><input type="checkbox" id="checkbox263" checked="true" /><label for="checkbox263">Support demonstration mode</label></li>
<li><input type="checkbox" id="checkbox17" checked="true" /><label for="checkbox17">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
<li><input type="checkbox" id="checkbox18" checked="true" /><label for="checkbox18">Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
<li><input type="checkbox" id="checkbox19" checked="true" /><label for="checkbox19">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
<li><input type="checkbox" id="checkbox20" checked="true" /><label for="checkbox20">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
<li><input type="checkbox" id="checkbox21" checked="true" /><label for="checkbox21">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, Support for expanding node content, and fully customize node content using DDM</label></li>
<li><input type="checkbox" id="checkbox22" checked="true" /><label for="checkbox22">Support canvas dragging and scaling</label></li>
<li><input type="checkbox" id="checkbox23" checked="true" /><label for="checkbox23">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
<li><input type="checkbox" id="checkbox24" checked="true" /><label for="checkbox24">Supoorts to export as </label><code>json</code><code>png</code><code>svg</code><code>pdf</code><code>markdown</code><code>xmind</code><code>txt</code>, support import from <code>json</code><code>xmind</code><code>markdown</code></li>
<li><input type="checkbox" id="checkbox25" checked="true" /><label for="checkbox25">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, scrollbar, Hand drawn style, and rainbow lines</label></li>
<li><input type="checkbox" id="checkbox26" checked="true" /><label for="checkbox26">Provide rich configurations to meet various scenarios and usage habits</label></li>
<li><input type="checkbox" id="checkbox27" checked="true" /><label for="checkbox27">Support collaborative editing</label></li>
<li><input type="checkbox" id="checkbox28" checked="true" /><label for="checkbox28">Support demonstration mode</label></li>
</ul>
<p>The official provides the following plugins, which can be introduced as needed (a certain function may not be effective because you did not introduce the corresponding plugin). Please refer to the documentation for specific usage methods:</p>
<blockquote>
@@ -39,16 +39,16 @@ frameworks such as Vue and React, or without a framework.</p>
<p>This is an online mind map built using the <code>simple-mind-map</code> library and based
on <code>Vue2.x</code> and <code>ElementUI</code>. Features include:</p>
<ul>
<li><input type="checkbox" id="checkbox264" checked="true" /><label for="checkbox264">Toolbar, which supports inserting and deleting nodes, and editing node</label>
<li><input type="checkbox" id="checkbox29" checked="true" /><label for="checkbox29">Toolbar, which supports inserting and deleting nodes, and editing node</label>
images, icons, hyperlinks, notes, tags, and summaries</li>
<li><input type="checkbox" id="checkbox265" checked="true" /><label for="checkbox265">Sidebar, with panels for basic style settings, node style settings,</label>
<li><input type="checkbox" id="checkbox30" checked="true" /><label for="checkbox30">Sidebar, with panels for basic style settings, node style settings,</label>
outline, theme selection, and structure selection</li>
<li><input type="checkbox" id="checkbox266" checked="true" /><label for="checkbox266">Import and export functionality; data is saved in the browser's local</label>
<li><input type="checkbox" id="checkbox31" checked="true" /><label for="checkbox31">Import and export functionality; data is saved in the browser's local</label>
storage by default, but it also supports creating, opening, and editing
local files on the computer directly</li>
<li><input type="checkbox" id="checkbox267" checked="true" /><label for="checkbox267">Right-click menu, which supports operations such as expanding, collapsing,</label>
<li><input type="checkbox" id="checkbox32" checked="true" /><label for="checkbox32">Right-click menu, which supports operations such as expanding, collapsing,</label>
and organizing layout</li>
<li><input type="checkbox" id="checkbox268" checked="true" /><label for="checkbox268">Bottom bar, which supports node and word count statistics, switching</label>
<li><input type="checkbox" id="checkbox33" checked="true" /><label for="checkbox33">Bottom bar, which supports node and word count statistics, switching</label>
between edit and read-only modes, zooming in and out, and switching to
full screen, support mini map</li>
</ul>
@@ -338,7 +338,7 @@ full screen, support mini map</li>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/孟照星.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>孟照星</p>
<p>Alex</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/子豪.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
@@ -348,6 +348,22 @@ full screen, support mini map</li>
<img src="../../../../assets/avatar/宏涛.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>宏涛</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/最多5个字.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>最多5个字</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/雨馨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>雨馨</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/ZX.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>ZX</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/峰.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p></p>
</div>
</div>
</div>
</template>

View File

@@ -506,6 +506,16 @@ Put the specified DOM element into full screen mode.
Exit full screen mode.
#### defenseXSS(htmlStr)
> v0.10.0+
- `htmlStr`HTML strings that need to be filtered
ReturnFiltered HTML string
Defend against XSS attacks, filter malicious HTML tags and attributes. You can recursively traverse the tree data before passing the node data to SimpleMindMap, using this method to process the rich text content of nodes and avoid XSS attacks.
## Simulate CSS background in Canvas
Import:

View File

@@ -424,6 +424,15 @@ and copying the <code>data</code> of the data object, example:</p>
<p>v0.9.11+</p>
</blockquote>
<p>Exit full screen mode.</p>
<h4>defenseXSS(htmlStr)</h4>
<blockquote>
<p>v0.10.0+</p>
</blockquote>
<ul>
<li><code>htmlStr</code>HTML strings that need to be filtered</li>
</ul>
<p>ReturnFiltered HTML string</p>
<p>Defend against XSS attacks, filter malicious HTML tags and attributes. You can recursively traverse the tree data before passing the node data to SimpleMindMap, using this method to process the rich text content of nodes and avoid XSS attacks.</p>
<h2>Simulate CSS background in Canvas</h2>
<p>Import:</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils/simulateCSSBackgroundInCanvas&#x27;</span>

View File

@@ -22,13 +22,15 @@ simpleMindMap.xmind
## Methods
### xmind.parseXmindFile(file)
### xmind.parseXmindFile(file, handleMultiCanvas)
Parsing the `.xmind` file and returning the parsed data. You can use
`mindMap.setData(data)` to render the returned data to the canvas.
`file`: `File` object
`handleMultiCanvas`v0.10.0+Optional, a function can be passed. If there are multiple canvases in the imported xmind file, this function will be called. The function takes the xmind canvas list data as a parameter and needs to return the data of one of the canvases, For example, if the received parameter is 'content', if you want to import data from the second canvas, you will return 'content[1]'. A function can be an asynchronous function that returns a Promise instance.
### xmind.transformXmind(content)
> V0.6.6+version changes the method to asynchronous and returns a Promise instance

View File

@@ -14,10 +14,11 @@
<pre class="hljs"><code>simpleMindMap.xmind
</code></pre>
<h2>Methods</h2>
<h3>xmind.parseXmindFile(file)</h3>
<h3>xmind.parseXmindFile(file, handleMultiCanvas)</h3>
<p>Parsing the <code>.xmind</code> file and returning the parsed data. You can use
<code>mindMap.setData(data)</code> to render the returned data to the canvas.</p>
<p><code>file</code>: <code>File</code> object</p>
<p><code>handleMultiCanvas</code>v0.10.0+Optional, a function can be passed. If there are multiple canvases in the imported xmind file, this function will be called. The function takes the xmind canvas list data as a parameter and needs to return the data of one of the canvases, For example, if the received parameter is 'content', if you want to import data from the second canvas, you will return 'content[1]'. A function can be an asynchronous function that returns a Promise instance.</p>
<h3>xmind.transformXmind(content)</h3>
<blockquote>
<p>V0.6.6+version changes the method to asynchronous and returns a Promise instance</p>

View File

@@ -35,6 +35,7 @@ export default [
{ path: 'course26', title: '如何实现AI生成节点内容' },
{ path: 'course27', title: '快捷键操作如何传递自定义参数' },
{ path: 'course28', title: '如何动态修改自定义元素的大小' },
{ path: 'course29', title: '局域网docker部署解决HTTPS问题的一种方法' },
{ path: 'doExport', title: 'Export 插件' },
{ path: 'drag', title: 'Drag插件' },
{ path: 'introduction', title: '简介' },
@@ -69,7 +70,8 @@ export default [
{ path: 'help2', title: '客户端' },
{ path: 'help3', title: '打开预览在线文件' },
{ path: 'help4', title: '复制粘贴' },
{ path: 'help5', title: '导出' }
{ path: 'help5', title: '导出' },
{ path: 'help6', title: '如何编辑数学公式' }
]
},
{

View File

@@ -1,5 +1,51 @@
# Changelog
## 0.10.0
较大更新:升级节点拖拽时的交互效果;
修复:
> 1.修复只读模式仍可通过Ctrl+点击节点方式激活节点的问题;
>
> 2.修复移动端部分浏览器设置缩放时会进行页面缩放的问题;
>
> 3.修复拖拽画布和拖拽调整图片时会选中文字的问题;
>
> 4.修复复制带换行符的节点文本粘贴后会出现多行换行的问题;
>
> 5.修复节点前后自定义内容导出图片时显示空白的问题;
新增:
> 1.新增渲染开始事件node_tree_render_start
>
> 2.支持设置水印显示在节点下方;
>
> 3.导入存在多个画布的xmind文件支持选择指定的画布进行导入
>
> 4.取消调用defenseXSS函数对性能影响太大defenseXSS方法作为工具方法提供
>
> 5.去除移除富文本内容中ql-cursor类名的节点的逻辑修复文本换行时新增空行不生效的问题
>
> 6.插入新节点时去除延时开启节点编辑的逻辑;
>
> 7.支持直接在富文本编辑框中编辑数学公式;
>
> 8.打包后的文件中增加演示插件;
Demo
> 1.支持配置水印显示在节点下方;
>
> 2.导入存在多个画布的xmind文件支持选择指定的画布进行导入
>
> 3.优化富文本工具条下拉选项列表高度问题;
>
> 4.新建和打开按钮增加导出的提示,防止内容丢失;
>
> 5.快捷键提示支持区分windows和mac
## 0.9.12
修复:

View File

@@ -1,6 +1,35 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.10.0</h2>
<p>较大更新升级节点拖拽时的交互效果</p>
<p>修复</p>
<blockquote>
<p>1.修复只读模式仍可通过Ctrl+点击节点方式激活节点的问题</p>
<p>2.修复移动端部分浏览器设置缩放时会进行页面缩放的问题</p>
<p>3.修复拖拽画布和拖拽调整图片时会选中文字的问题</p>
<p>4.修复复制带换行符的节点文本粘贴后会出现多行换行的问题</p>
<p>5.修复节点前后自定义内容导出图片时显示空白的问题</p>
</blockquote>
<p>新增</p>
<blockquote>
<p>1.新增渲染开始事件node_tree_render_start</p>
<p>2.支持设置水印显示在节点下方</p>
<p>3.导入存在多个画布的xmind文件支持选择指定的画布进行导入</p>
<p>4.取消调用defenseXSS函数对性能影响太大defenseXSS方法作为工具方法提供</p>
<p>5.去除移除富文本内容中ql-cursor类名的节点的逻辑修复文本换行时新增空行不生效的问题</p>
<p>6.插入新节点时去除延时开启节点编辑的逻辑</p>
<p>7.支持直接在富文本编辑框中编辑数学公式</p>
<p>8.打包后的文件中增加演示插件</p>
</blockquote>
<p>Demo</p>
<blockquote>
<p>1.支持配置水印显示在节点下方</p>
<p>2.导入存在多个画布的xmind文件支持选择指定的画布进行导入</p>
<p>3.优化富文本工具条下拉选项列表高度问题</p>
<p>4.新建和打开按钮增加导出的提示防止内容丢失</p>
<p>5.快捷键提示支持区分windows和mac</p>
</blockquote>
<h2>0.9.12</h2>
<p>修复</p>
<blockquote>

View File

@@ -22,6 +22,8 @@ const mindMap = new MindMap({
## 实例化选项
### 1.基本
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| el | Element | | 容器元素必传必须为DOM元素当容器元素在页面上的位置发生了改变但大小没有改变的情况下必须调用`getElRectInfo()`方法更新库内部的相关信息;当大小也发生了改变后必须调用`resize()`方法,否则会造成一些功能异常) |
@@ -32,15 +34,10 @@ const mindMap = new MindMap({
| themeConfig | Object | {} | 主题配置,会和所选择的主题进行合并,可用字段可参考:[default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) |
| scaleRatio | Number | 0.1 | 放大缩小的增量比例 |
| maxTag | Number | 5 | 节点里最多显示的标签数量,多余的会被丢弃 |
| exportPadding | Number | 20 | 导出图片时的内边距 |
| imgTextMargin | Number | 5 | 节点里图片和文字的间距 |
| textContentMargin | Number | 2 | 节点里各种文字信息的间距,如图标和文字的间距 |
| selectTranslateStep | Number | 3 | 多选节点时鼠标移动到边缘时的画布移动偏移量 |
| selectTranslateLimit | Number | 20 | 多选节点时鼠标移动距边缘多少距离时开始偏移 |
| customNoteContentShowv0.1.6+ | Object | null | 自定义节点备注内容显示Object类型结构为{show: (noteContent, left, top, node) => {// 你的显示节点备注逻辑。node为v0.8.1+版本新增的回参,代表节点实例 }, hide: () => {// 你的隐藏节点备注逻辑 }} |
| readonlyv0.1.7+ | Boolean | false | 是否是只读模式 |
| enableFreeDragv0.2.4+ | Boolean | false | 是否开启节点自由拖拽(自由拖拽即可以把节点拖拽到画布的任意位置,注意不是拖拽节点成为其他节点的子节点兄弟节点的功能,自由拖拽的连线会存在一定问题,所以该特性最好不要使用) |
| watermarkConfigv0.2.4+ | Object | | 水印配置,详细配置请参考下方表格【水印配置】 |
| textAutoWrapWidthv0.3.4+ | Number | 500 | 节点内每行文本达到该宽度后自动换行 |
| customHandleMousewheelv0.4.3+ | Function | null | 自定义鼠标滚轮事件处理,可以传一个函数,回调参数为事件对象 |
| mousewheelActionv0.4.3+ | String | zoomv0.9.1+默认改为move | 鼠标滚轮的行为,`zoom`(放大缩小)、`move`(上下移动)。如果`customHandleMousewheel`传了自定义函数,这个属性不生效 |
@@ -56,8 +53,6 @@ const mindMap = new MindMap({
| enableNodeTransitionMovev0.5.1+v0.6.7+已去除该特性) | Boolean | true | 是否开启节点动画过渡 |
| nodeTransitionMoveDurationv0.5.1+v0.6.7+已去除该特性) | Number | 300 | 如果开启节点动画过渡可以通过该属性设置过渡的时间单位ms |
| initRootNodePositionv0.5.3+ | Array | null | 初始根节点的位置,可传一个数组,默认为`['center', 'center']`,代表根节点处于画布中心位置,除了`center`,关键词还可以设置`left``top``right``bottom`,除了可以传关键词,数组的每项还可以传递一个数字,代表具体的像素,可以传递一个百分比字符串,比如`['40%', '60%']`,代表水平位置在画布宽度的`40%`的位置,垂直位置在画布高度的`60%`的位置 |
| exportPaddingXv0.5.5+ | Number | 10 | 导出png、svg、pdf时的图形水平内边距 |
| exportPaddingYv0.5.5+ | Number | 10 | 导出png、svg、pdf时的图形垂直内边距 |
| nodeTextEditZIndexv0.5.5+ | Number | 3000 | 节点文本编辑框元素的z-index |
| nodeNoteTooltipZIndexv0.5.5+ | Number | 3000 | 节点备注浮层元素的z-index |
| isEndNodeTextEditOnClickOuterv0.5.5+ | Boolean | true | 是否在点击了画布外的区域时结束节点文本的编辑状态 |
@@ -65,7 +60,6 @@ const mindMap = new MindMap({
| alwaysShowExpandBtnv0.5.8+ | Boolean | false | 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示 |
| iconListv0.5.8+ | Array | [] | 扩展节点可插入的图标,数组的每一项为一个对象,对象详细结构请参考下方【图标配置】表格 |
| maxNodeCacheCountv0.5.10+ | Number | 1000 | 节点最大缓存数量。为了优化性能,内部会维护一个节点缓存池,用来复用节点,通过该属性可以指定池的最大缓存数量 |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | 关联线默认文字 |
| fitPaddingv0.6.0+ | Number | 50 | 思维导图适应画布大小时的内边距单位px |
| enableCtrlKeyNodeSelectionv0.6.0+ | Boolean | true | 是否开启按住ctrl键多选节点的功能 |
| useLeftKeySelectionRightKeyDragv0.6.0+ | Boolean | false | 设置为左键多选节点,右键拖动画布 |
@@ -74,55 +68,36 @@ const mindMap = new MindMap({
| customCreateNodeContentv0.6.3+ | Function/null | null | 如果`isUseCustomNodeContent`设为`true`,那么需要使用该选项传入一个方法,接收节点实例`node`为参数(如果要获取该节点的数据,可以通过`node.nodeData.data`需要返回自定义节点内容元素也就是DOM节点如果某个节点不需要自定义那么返回`null`即可 |
| mouseScaleCenterUseMousePositionv0.6.4-fix.1+ | Boolean | true | 鼠标缩放是否以鼠标当前位置为中心点,否则以画布中心点 |
| customInnerElsAppendTov0.6.12+ | null/HTMLElement | null | 指定内部一些元素节点文本编辑元素、节点备注显示元素、关联线文本编辑元素、节点图片调整按钮元素添加到的位置默认添加到document.body下 |
| nodeDragPlaceholderMaxSizev0.6.12+ | Number | 20 | 拖拽元素时,指示元素新位置的块的最大高度 |
| enableCreateHiddenInputv0.6.13+v0.6.14+版本已去除该特性) | Boolean | true | 是否允许创建一个隐藏的输入框,该输入框会在节点激活时聚焦,用于粘贴数据和自动进入文本编辑状态 |
| enableAutoEnterTextEditWhenKeydownv0.6.13+ | Boolean | true | 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式 |
| richTextEditFakeInPlacev0.6.13+ | Boolean | false | 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果,需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果 |
| customHandleClipboardTextv0.6.14+ | Function | null | 自定义对剪贴板文本的处理。当按ctrl+v粘贴时会读取用户剪贴板中的文本和图片默认只会判断文本是否是普通文本和simple-mind-map格式的节点数据如果你想处理其他思维导图的数据比如processon、zhixi等那么可以传递一个函数接受当前剪贴板中的文本为参数返回处理后的数据可以返回两种类型1.返回一个纯文本那么会直接以该文本创建一个子节点2.返回一个节点对象,格式如下:{ simpleMindMap: true, data: { data: { text: '' }, children: [] } }代表是simple-mind-map格式的数据节点数据同simple-mind-map节点数据格式如果你的处理逻辑存在异步逻辑也可以返回一个promise |
| errorHandlerv0.6.15+ | Function | | 自定义错误处理函数,目前只会抛出一些异步逻辑出错的情况。可以传递一个函数,会接收两个参数,第一个为错误的类型,第二个为错误对象 |
| disableMouseWheelZoomv0.6.15+ | Boolean | false | 禁止鼠标滚轮缩放你仍旧可以使用api进行缩放 |
| resetCssv0.6.16+ | String | * { margin: 0; padding: 0; box-sizing: border-box; } | 设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖如果不覆盖节点内容会发生偏移 |
| enableDblclickResetv0.6.17+v0.8.0+已删除该属性) | Boolean | truev0.7.0+改为false | 开启鼠标双击复位思维导图位置及缩放 |
| enableDblclickBackToRootNodev0.8.0+ | Boolean | false | 是否在鼠标双击时回到根节点,也就是让根节点居中显示 |
| minExportImgCanvasScalev0.7.0+ | Number | 2 | 导出图片和pdf时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值用于提升图片清晰度 |
| hoverRectColorv0.7.0+ | String | rgb(94, 200, 248) | 节点鼠标hover和激活时显示的矩形边框颜色hover时会添加0.6的透明度 |
| hoverRectPaddingv0.7.0+ | Number | 2 | 节点鼠标hover和激活时显示的矩形边框距节点内容的距离 |
| selectTextOnEnterEditTextv0.7.0+ | Boolean | true | 双击节点进入节点文本编辑时是否默认选中文本,默认只在创建新节点时会选中 |
| deleteNodeActivev0.7.1+ | Boolean | true | 是否开启删除节点后自动激活节点相邻节点或父节点的功能 |
| autoMoveWhenMouseInEdgeOnDragv0.7.1+ | Boolean | true | 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动 |
| fitv0.7.1-fix.2+ | Boolean | false | 首次渲染时是否缩放至适应画布大小 |
| dragMultiNodeRectConfigv0.7.2+ | Object | { width: 40, height: 20, fill: '' } | 拖拽多个节点时随鼠标移动的示意矩形的样式配置,传递一个对象,字段含义分别为矩形的宽、高、填充色 |
| dragPlaceholderRectFillv0.7.2+ | String | | 节点拖拽时新位置的示意矩形的填充颜色,如果不传默认使用连线的颜色 |
| dragOpacityConfigv0.7.2+ | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | 节点拖拽时的透明度配置,传递一个对象,字段含义分别为:跟随鼠标移动的克隆节点或矩形的透明度、被拖拽节点的透明度 |
| tagsColorMapv0.7.2+ | Object | {} | 自定义节点标签的颜色可传一个对象key为要指定颜色的标签内容value为该标签内容的颜色如果不传内部会根据标签内容生成对应的颜色 |
| cooperateStylev0.7.3+ | Object | { avatarSize: 22, fontSize: 12 } | 节点协作编辑时的人员头像样式配置,字段含义分别为:头像大小、如果是文字头像,那么文字的大小 |
| associativeLineIsAlwaysAboveNodev0.8.0+ | Boolean | true | 关联线是否始终显示在节点上层如果设为false那么创建关联线和激活关联线时处于最顶层其他情况下处于节点下方 |
| onlyOneEnableActiveNodeOnCooperatev0.9.8+ | Boolean | false | 协同编辑时,同一个节点不能同时被多人选中 |
| defaultGeneralizationTextv0.8.0+ | String | 概要 | 插入概要的默认文本 |
| handleIsSplitByWrapOnPasteCreateNewNodev0.8.0+ | Function / null | null | 粘贴文本的方式创建新节点时控制是否按换行自动分割节点即如果存在换行那么会根据换行创建多个节点否则只会创建一个节点可以传递一个函数返回promiseresolve代表根据换行分割reject代表忽略换行 |
| addHistoryTimev0.8.0+ | Number | 100 | 指定时间内只允许添加一次历史记录避免添加没有必要的中间状态单位ms |
| isDisableDragv0.8.1+ | Boolean | false | 是否禁止拖动画布 |
| disableTouchZoomv0.8.1+ | Boolean | false | 禁止双指缩放你仍旧可以使用api进行缩放对TouchEvent插件生效 |
| highlightNodeBoxStylev0.9.0+ | Object | { stroke: 'rgb(94, 200, 248)', fill: 'transparent' } | 鼠标移入概要高亮所属节点时的高亮框样式 |
| createNewNodeBehaviorv0.9.1+ | String | default | 创建新节点时的行为。default默认会激活新创建的节点并且进入编辑模式。如果同时创建了多个新节点那么只会激活而不会进入编辑模式、notActive不激活新创建的节点、activeOnly只激活新创建的节点不进入编辑模式 |
| defaultNodeImagev0.9.1-fix.2+ | String | | 图片地址,当节点图片加载失败时显示的默认图片 |
| handleNodePasteImgv0.9.2+ | null 或 Function | null | 在节点上粘贴剪贴板中的图片的处理方法默认是转换为data:url数据插入到节点中你可以通过该方法来将图片数据上传到服务器实现保存图片的url。可以传递一个异步方法接收Blob类型的图片数据需要返回指定结构{ url, size: {width, height} } |
| isLimitMindMapInCanvasv0.9.2+ | Boolean | false | 是否将思维导图限制在画布内。比如向右拖动时,思维导图图形的最左侧到达画布中心时将无法继续向右拖动,其他同理 |
| isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+ | Boolean | true | 当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas配置不再起作用 |
| associativeLineInitPointsPositionv0.9.5+ | null / { from, to } | { from: '', to: '' } | 默认情况下新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的如果你想固定位置可以通过这个选项来配置。from和to都不传则都自动计算如果只传一个另一个则会自动计算。from和to可选值left、top、bottom、right |
| enableAdjustAssociativeLinePointsv0.9.5+ | Boolean | true | 是否允许调整关联线两个端点的位置 |
| isOnlySearchCurrentRenderNodesv0.9.8+ | Boolean | false | 是否仅搜索当前渲染的节点,被收起的节点不会被搜索到 |
| onlyOneEnableActiveNodeOnCooperatev0.9.8+ | Boolean | false | 协同编辑时,同一个节点不能同时被多人选中 |
| beforeCooperateUpdatev0.9.8+ | Function、null | null | 协同编辑时,节点操作即将更新到其他客户端前的生命周期函数。函数接收一个对象作为参数:{ type: 【createOrUpdate创建节点或更新节点、delete删除节点】, list: 【数组类型1.当type=createOrUpdate时代表被创建或被更新的节点数据即将同步到其他客户端所以你可以修改该数据2.当type=delete时代表被删除的节点数据】 } |
| beforeShortcutRunv0.9.9+ | Function、null | null | 快捷键操作即将执行前的生命周期函数返回true可以阻止操作执行。函数接收两个参数key快捷键、activeNodeList当前激活的节点列表 |
| rainbowLinesConfigv0.9.9+ | Object | { open: false, colorsList: [] } | 彩虹线条配置需要先注册RainbowLines插件。对象类型结构{ open: false【是否开启彩虹线条】, colorsList: []【自定义彩虹线条的颜色列表,如果不设置,会使用默认颜色列表】 } |
| addContentToHeaderv0.9.9+ | Function、null | null | 导出png、svg、pdf时在头部添加自定义内容。可传递一个函数这个函数可以返回null代表不添加内容也可以返回一个对象详细介绍请参考下方【导出时如何添加自定义内容】 |
| addContentToFooterv0.9.9+ | Function、null | null | 基本释义同addContentToHeader在尾部添加自定义内容 |
| demonstrateConfigv0.9.11+ | Object、null | null | 演示插件Demonstrate的配置。不传则使用默认配置可传递一个对象如果只配置某个属性可以只设置该属性其他没有设置的同样会使用默认配置完整配置请参考下方【演示插件配置】小节 |
| resetScaleOnMoveNodeToCenterv0.9.12+ | Boolean | false | 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%底层影响的是render类的moveNodeToCenter方法 |
| createNodePrefixContentv0.9.12+ | Function、null | null | 添加附加的节点前置内容。前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。可以传递一个函数,这个函数接收一个节点实例的参数,可以返回一个DOM节点也可以返回null |
| createNodePostfixContentv0.9.12+ | Function、null | null | 添加附加的节点后置内容。后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分。可以传递一个函数这个函数接收一个节点实例的参数可以返回一个DOM节点也可以返回null |
| createNodePrefixContentv0.9.12+ | Function、null | null | 添加附加的节点前置内容。前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。可以传递一个函数,这个函数接收一个节点实例的参数,可以返回{el, width, height}格式的对象el为DOM节点对象width和height代表内容的宽高数字类型如果不需要自定义内容也可以返回null |
| createNodePostfixContentv0.9.12+ | Function、null | null | 添加附加的节点后置内容。后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分。用法同createNodePrefixContent |
### 数据结构
#### 1.1数据结构
基本的数据结构如下:
@@ -167,18 +142,7 @@ const mindMap = new MindMap({
如果你要添加自定义的字段,可以添加到`data``children`同级,如果你要添加到`data`对象里,那么请使用`_`开头来命名你的自定义字段,内部会通过这个来判断是否是自定义字段。
### 水印配置
| 字段名称 | 类型 | 默认值 | 描述 |
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
| text | String | '' | 水印文字,如果为空字符串则不显示水印 |
| lineSpacing | Number | 100 | 水印每行之间的间距 |
| textSpacing | Number | 100 | 同一行水印之间的间距 |
| angle | Number | 30 | 水印的倾斜角度,范围:[0, 90] |
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | 水印文字样式 |
| onlyExportv0.9.2+ | Boolean | false | 是否仅在导出时添加水印 |
### 图标配置
#### 1.2图标配置
| 字段名称 | 类型 | 默认值 | 描述 |
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
@@ -186,7 +150,20 @@ const mindMap = new MindMap({
| type | String | | 图标分组的值 |
| list | Array | | 分组下的图标列表,数组的每一项为一个对象,`{ name: '', icon: '' }``name`代表图标的名称,`icon`代表图标,可以是`svg`图标,比如`<svg ...><path></path></svg>`,也可以是图片`url`,或者是`base64`图标,比如`data:image/png;base64,...` |
### 导出时如何添加自定义内容
### 2.Export插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| exportPadding已废除 | Number | 20 | 导出图片时的内边距 |
| exportPaddingXv0.5.5+ | Number | 10 | 导出png、svg、pdf时的图形水平内边距 |
| exportPaddingYv0.5.5+ | Number | 10 | 导出png、svg、pdf时的图形垂直内边距 |
| resetCssv0.6.16+ | String | * { margin: 0; padding: 0; box-sizing: border-box; } | 设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖如果不覆盖节点内容会发生偏移 |
| minExportImgCanvasScalev0.7.0+ | Number | 2 | 导出图片和pdf时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值用于提升图片清晰度 |
| addContentToHeaderv0.9.9+ | Function、null | null | 导出png、svg、pdf时在头部添加自定义内容。可传递一个函数这个函数可以返回null代表不添加内容也可以返回一个对象详细介绍请参考下方【导出时如何添加自定义内容】 |
| addContentToFooterv0.9.9+ | Function、null | null | 基本释义同addContentToHeader在尾部添加自定义内容 |
#### 2.1导出时如何添加自定义内容
`addContentToHeader``addContentToFooter`两个实例化选项可以用于在导出`png``svg``pdf`时在头部和尾部添加自定义的内容,默认为`null`,代表不配置,可以传递一个函数,函数可以返回`null`,代表不添加内容,如果要添加内容那么需要返回如下的结构:
@@ -221,7 +198,98 @@ new MindMap({
})
```
### 演示插件配置
### 3.Select插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| selectTranslateStep | Number | 3 | 多选节点时鼠标移动到边缘时的画布移动偏移量 |
| selectTranslateLimit | Number | 20 | 多选节点时鼠标移动距边缘多少距离时开始偏移 |
### 4.Drag插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| enableFreeDragv0.2.4+ | Boolean | false | 是否开启节点自由拖拽(自由拖拽即可以把节点拖拽到画布的任意位置,注意不是拖拽节点成为其他节点的子节点兄弟节点的功能,自由拖拽的连线会存在一定问题,所以该特性最好不要使用) |
| nodeDragPlaceholderMaxSizev0.6.12+v0.10.0+已废除) | Number | 20 | 拖拽元素时,指示元素新位置的块的最大高度 |
| autoMoveWhenMouseInEdgeOnDragv0.7.1+ | Boolean | true | 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动 |
| dragMultiNodeRectConfigv0.7.2+ | Object | { width: 40, height: 20, fill: 'rgb(94, 200, 248)' } | 拖拽多个节点时随鼠标移动的示意矩形的样式配置,传递一个对象,字段含义分别为矩形的宽、高、填充色 |
| dragPlaceholderRectFillv0.7.2+ | String | rgb(94, 200, 248) | 节点拖拽时新位置的示意矩形的填充颜色 |
| dragPlaceholderLineConfigv0.10.0+ | Object | { color: 'rgb(94, 200, 248)', width: 2 } | 节点拖拽时新位置的示意连线的样式配置 |
| dragOpacityConfigv0.7.2+ | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | 节点拖拽时的透明度配置,传递一个对象,字段含义分别为:跟随鼠标移动的克隆节点或矩形的透明度、被拖拽节点的透明度 |
### 5.Watermark插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| watermarkConfigv0.2.4+ | Object | | 水印配置,详细配置请参考下方表格【水印配置】 |
#### 5.1水印配置
| 字段名称 | 类型 | 默认值 | 描述 |
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
| text | String | '' | 水印文字,如果为空字符串则不显示水印 |
| lineSpacing | Number | 100 | 水印每行之间的间距 |
| textSpacing | Number | 100 | 同一行水印之间的间距 |
| angle | Number | 30 | 水印的倾斜角度,范围:[0, 90] |
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | 水印文字样式 |
| onlyExportv0.9.2+ | Boolean | false | 是否仅在导出时添加水印 |
| belowNodev0.10.0+ | Boolean | false | 水印是否显示在节点下方 |
### 6.AssociativeLine插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | 关联线默认文字 |
| associativeLineIsAlwaysAboveNodev0.8.0+ | Boolean | true | 关联线是否始终显示在节点上层如果设为false那么创建关联线和激活关联线时处于最顶层其他情况下处于节点下方 |
| associativeLineInitPointsPositionv0.9.5+ | null / { from, to } | { from: '', to: '' } | 默认情况下新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的如果你想固定位置可以通过这个选项来配置。from和to都不传则都自动计算如果只传一个另一个则会自动计算。from和to可选值left、top、bottom、right |
| enableAdjustAssociativeLinePointsv0.9.5+ | Boolean | true | 是否允许调整关联线两个端点的位置 |
### 7.RichText插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| richTextEditFakeInPlacev0.6.13+ | Boolean | false | 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果,需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果 |
| enableEditFormulaInRichTextEditv0.10.0+ | Boolean | true | 是否开启在富文本编辑框中直接编辑数学公式 |
| transformRichTextOnEnterEditv0.10.0+ | null、Function | null | 转换富文本内容,可以传递一个函数,当进入富文本编辑时会调用该函数,函数接收即将被编辑的富文本内容,需要返回你处理后的富文本内容 |
| beforeHideRichTextEditv0.10.0+ | null、Function | null | 可以传递一个函数即将结束富文本编辑前会执行该函数函数接收richText实例所以你可以在此时机更新quill文档数据 |
### 8.TouchEvent插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| disableTouchZoomv0.8.1+ | Boolean | false | 禁止双指缩放你仍旧可以使用api进行缩放对TouchEvent插件生效 |
### 9.Scrollbar插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+ | Boolean | true | 当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas配置不再起作用 |
### 10.Search插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| isOnlySearchCurrentRenderNodesv0.9.8+ | Boolean | false | 是否仅搜索当前渲染的节点,被收起的节点不会被搜索到 |
### 11.Cooperate插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| beforeCooperateUpdatev0.9.8+ | Function、null | null | 协同编辑时,节点操作即将更新到其他客户端前的生命周期函数。函数接收一个对象作为参数:{ type: 【createOrUpdate创建节点或更新节点、delete删除节点】, list: 【数组类型1.当type=createOrUpdate时代表被创建或被更新的节点数据即将同步到其他客户端所以你可以修改该数据2.当type=delete时代表被删除的节点数据】 } |
### 12.RainbowLines插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| rainbowLinesConfigv0.9.9+ | Object | { open: false, colorsList: [] } | 彩虹线条配置需要先注册RainbowLines插件。对象类型结构{ open: false【是否开启彩虹线条】, colorsList: []【自定义彩虹线条的颜色列表,如果不设置,会使用默认颜色列表】 } |
### 13.Demonstrate插件
| 字段名称 | 类型 | 默认值 | 描述 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
| demonstrateConfigv0.9.11+ | Object、null | null | 演示插件Demonstrate的配置。不传则使用默认配置可传递一个对象如果只配置某个属性可以只设置该属性其他没有设置的同样会使用默认配置完整配置请参考下方【演示插件配置】小节 |
#### 13.1演示插件配置
| 字段名称 | 类型 | 默认值 | 描述 |
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
@@ -484,7 +552,8 @@ mindMap.setTheme('主题名称')
| node_img_mouseenterv0.6.5+ | 节点内图片的鼠标移入事件 | this节点实例、imgNode图片节点、e事件对象 |
| node_img_mouseleavev0.6.5+ | 节点内图片的鼠标移出事件 | this节点实例、imgNode图片节点、e事件对象 |
| node_img_mousemovev0.6.5+ | 节点内图片的鼠标移动事件 | this节点实例、imgNode图片节点、e事件对象 |
| node_tree_render_endv0.2.16+ | 节点树渲染完毕事件 | |
| node_tree_render_endv0.2.16+ | 节点树渲染完毕事件 | |
| node_tree_render_startv0.10.0+ | 节点树开始渲染事件 | |
| rich_text_selection_changev0.4.0+ | 当注册了`RichText`插件时可用。当节点编辑时,文本选区发生改变时触发 | hasRange是否存在选区、rectInfo选区的尺寸和位置信息、formatInfo选区的文本格式化信息 |
| transforming-dom-to-imagesv0.4.0+ | 当注册了`RichText`插件时可用。当`svg`中存在`DOM`节点时,导出为图片时会将`DOM`节点转换为图片,转换过程中会触发该事件,可用通过该事件给用户提示,告知目前转换到的节点 | index当前转换到的节点索引、len一共需要转换的节点数量 |
| node_draggingv0.4.5+ | 当某个节点被拖拽时触发 | node当前被拖拽的节点 |

View File

@@ -17,6 +17,7 @@
});
</code></pre>
<h2>实例化选项</h2>
<h3>1.基本</h3>
<table>
<thead>
<tr>
@@ -76,12 +77,6 @@
<td>节点里最多显示的标签数量多余的会被丢弃</td>
</tr>
<tr>
<td>exportPadding</td>
<td>Number</td>
<td>20</td>
<td>导出图片时的内边距</td>
</tr>
<tr>
<td>imgTextMargin</td>
<td>Number</td>
<td>5</td>
@@ -94,18 +89,6 @@
<td>节点里各种文字信息的间距如图标和文字的间距</td>
</tr>
<tr>
<td>selectTranslateStep</td>
<td>Number</td>
<td>3</td>
<td>多选节点时鼠标移动到边缘时的画布移动偏移量</td>
</tr>
<tr>
<td>selectTranslateLimit</td>
<td>Number</td>
<td>20</td>
<td>多选节点时鼠标移动距边缘多少距离时开始偏移</td>
</tr>
<tr>
<td>customNoteContentShowv0.1.6+</td>
<td>Object</td>
<td>null</td>
@@ -118,18 +101,6 @@
<td>是否是只读模式</td>
</tr>
<tr>
<td>enableFreeDragv0.2.4+</td>
<td>Boolean</td>
<td>false</td>
<td>是否开启节点自由拖拽自由拖拽即可以把节点拖拽到画布的任意位置注意不是拖拽节点成为其他节点的子节点兄弟节点的功能自由拖拽的连线会存在一定问题所以该特性最好不要使用</td>
</tr>
<tr>
<td>watermarkConfigv0.2.4+</td>
<td>Object</td>
<td></td>
<td>水印配置详细配置请参考下方表格水印配置</td>
</tr>
<tr>
<td>textAutoWrapWidthv0.3.4+</td>
<td>Number</td>
<td>500</td>
@@ -220,18 +191,6 @@
<td>初始根节点的位置可传一个数组默认为<code>['center', 'center']</code>代表根节点处于画布中心位置除了<code>center</code>关键词还可以设置<code>left</code><code>top</code><code>right</code><code>bottom</code>除了可以传关键词数组的每项还可以传递一个数字代表具体的像素可以传递一个百分比字符串比如<code>['40%', '60%']</code>代表水平位置在画布宽度的<code>40%</code>的位置垂直位置在画布高度的<code>60%</code>的位置</td>
</tr>
<tr>
<td>exportPaddingXv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>导出pngsvgpdf时的图形水平内边距</td>
</tr>
<tr>
<td>exportPaddingYv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>导出pngsvgpdf时的图形垂直内边距</td>
</tr>
<tr>
<td>nodeTextEditZIndexv0.5.5+</td>
<td>Number</td>
<td>3000</td>
@@ -274,12 +233,6 @@
<td>节点最大缓存数量为了优化性能内部会维护一个节点缓存池用来复用节点通过该属性可以指定池的最大缓存数量</td>
</tr>
<tr>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td>关联</td>
<td>关联线默认文字</td>
</tr>
<tr>
<td>fitPaddingv0.6.0+</td>
<td>Number</td>
<td>50</td>
@@ -328,12 +281,6 @@
<td>指定内部一些元素节点文本编辑元素节点备注显示元素关联线文本编辑元素节点图片调整按钮元素添加到的位置默认添加到document.body下</td>
</tr>
<tr>
<td>nodeDragPlaceholderMaxSizev0.6.12+</td>
<td>Number</td>
<td>20</td>
<td>拖拽元素时指示元素新位置的块的最大高度</td>
</tr>
<tr>
<td>enableCreateHiddenInputv0.6.13+v0.6.14+版本已去除该特性</td>
<td>Boolean</td>
<td>true</td>
@@ -346,12 +293,6 @@
<td>是否在存在一个激活节点时当按下中文英文数字按键时自动进入文本编辑模式</td>
</tr>
<tr>
<td>richTextEditFakeInPlacev0.6.13+</td>
<td>Boolean</td>
<td>false</td>
<td>设置富文本节点编辑框和节点大小一致形成伪原地编辑的效果需要注意的是只有当节点内只有文本且形状是矩形才会有比较好的效果</td>
</tr>
<tr>
<td>customHandleClipboardTextv0.6.14+</td>
<td>Function</td>
<td>null</td>
@@ -370,12 +311,6 @@
<td>禁止鼠标滚轮缩放你仍旧可以使用api进行缩放</td>
</tr>
<tr>
<td>resetCssv0.6.16+</td>
<td>String</td>
<td>* { margin: 0; padding: 0; box-sizing: border-box; }</td>
<td>设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖如果不覆盖节点内容会发生偏移</td>
</tr>
<tr>
<td>enableDblclickResetv0.6.17+v0.8.0+已删除该属性</td>
<td>Boolean</td>
<td>truev0.7.0+改为false</td>
@@ -388,12 +323,6 @@
<td>是否在鼠标双击时回到根节点也就是让根节点居中显示</td>
</tr>
<tr>
<td>minExportImgCanvasScalev0.7.0+</td>
<td>Number</td>
<td>2</td>
<td>导出图片和pdf时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值用于提升图片清晰度</td>
</tr>
<tr>
<td>hoverRectColorv0.7.0+</td>
<td>String</td>
<td>rgb(94, 200, 248)</td>
@@ -418,36 +347,12 @@
<td>是否开启删除节点后自动激活节点相邻节点或父节点的功能</td>
</tr>
<tr>
<td>autoMoveWhenMouseInEdgeOnDragv0.7.1+</td>
<td>Boolean</td>
<td>true</td>
<td>拖拽节点时鼠标移动到画布边缘是否开启画布自动移动</td>
</tr>
<tr>
<td>fitv0.7.1-fix.2+</td>
<td>Boolean</td>
<td>false</td>
<td>首次渲染时是否缩放至适应画布大小</td>
</tr>
<tr>
<td>dragMultiNodeRectConfigv0.7.2+</td>
<td>Object</td>
<td>{ width: 40, height: 20, fill: '' }</td>
<td>拖拽多个节点时随鼠标移动的示意矩形的样式配置传递一个对象字段含义分别为矩形的宽填充色</td>
</tr>
<tr>
<td>dragPlaceholderRectFillv0.7.2+</td>
<td>String</td>
<td></td>
<td>节点拖拽时新位置的示意矩形的填充颜色如果不传默认使用连线的颜色</td>
</tr>
<tr>
<td>dragOpacityConfigv0.7.2+</td>
<td>Object</td>
<td>{ cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 }</td>
<td>节点拖拽时的透明度配置传递一个对象字段含义分别为跟随鼠标移动的克隆节点或矩形的透明度被拖拽节点的透明度</td>
</tr>
<tr>
<td>tagsColorMapv0.7.2+</td>
<td>Object</td>
<td>{}</td>
@@ -460,10 +365,10 @@
<td>节点协作编辑时的人员头像样式配置字段含义分别为头像大小如果是文字头像那么文字的大小</td>
</tr>
<tr>
<td>associativeLineIsAlwaysAboveNodev0.8.0+</td>
<td>onlyOneEnableActiveNodeOnCooperatev0.9.8+</td>
<td>Boolean</td>
<td>true</td>
<td>关联线是否始终显示在节点上层如果设为false那么创建关联线和激活关联线时处于最顶层其他情况下处于节点下方</td>
<td>false</td>
<td>协同编辑时同一个节点不能同时被多人选中</td>
</tr>
<tr>
<td>defaultGeneralizationTextv0.8.0+</td>
@@ -490,12 +395,6 @@
<td>是否禁止拖动画布</td>
</tr>
<tr>
<td>disableTouchZoomv0.8.1+</td>
<td>Boolean</td>
<td>false</td>
<td>禁止双指缩放你仍旧可以使用api进行缩放对TouchEvent插件生效</td>
</tr>
<tr>
<td>highlightNodeBoxStylev0.9.0+</td>
<td>Object</td>
<td>{ stroke: 'rgb(94, 200, 248)', fill: 'transparent' }</td>
@@ -526,72 +425,12 @@
<td>是否将思维导图限制在画布内比如向右拖动时思维导图图形的最左侧到达画布中心时将无法继续向右拖动其他同理</td>
</tr>
<tr>
<td>isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+</td>
<td>Boolean</td>
<td>true</td>
<td>当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas配置不再起作用</td>
</tr>
<tr>
<td>associativeLineInitPointsPositionv0.9.5+</td>
<td>null / { from, to }</td>
<td>{ from: '', to: '' }</td>
<td>默认情况下新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的如果你想固定位置可以通过这个选项来配置from和to都不传则都自动计算如果只传一个另一个则会自动计算from和to可选值lefttopbottomright</td>
</tr>
<tr>
<td>enableAdjustAssociativeLinePointsv0.9.5+</td>
<td>Boolean</td>
<td>true</td>
<td>是否允许调整关联线两个端点的位置</td>
</tr>
<tr>
<td>isOnlySearchCurrentRenderNodesv0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>是否仅搜索当前渲染的节点被收起的节点不会被搜索到</td>
</tr>
<tr>
<td>onlyOneEnableActiveNodeOnCooperatev0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>协同编辑时同一个节点不能同时被多人选中</td>
</tr>
<tr>
<td>beforeCooperateUpdatev0.9.8+</td>
<td>Functionnull</td>
<td>null</td>
<td>协同编辑时节点操作即将更新到其他客户端前的生命周期函数函数接收一个对象作为参数{ type: createOrUpdate创建节点或更新节点delete删除节点, list: 数组类型1.当type=createOrUpdate时代表被创建或被更新的节点数据即将同步到其他客户端所以你可以修改该数据2.当type=delete时代表被删除的节点数据 }</td>
</tr>
<tr>
<td>beforeShortcutRunv0.9.9+</td>
<td>Functionnull</td>
<td>null</td>
<td>快捷键操作即将执行前的生命周期函数返回true可以阻止操作执行函数接收两个参数key快捷键activeNodeList当前激活的节点列表</td>
</tr>
<tr>
<td>rainbowLinesConfigv0.9.9+</td>
<td>Object</td>
<td>{ open: false, colorsList: [] }</td>
<td>彩虹线条配置需要先注册RainbowLines插件对象类型结构{ open: false是否开启彩虹线条, colorsList: []自定义彩虹线条的颜色列表如果不设置会使用默认颜色列表 }</td>
</tr>
<tr>
<td>addContentToHeaderv0.9.9+</td>
<td>Functionnull</td>
<td>null</td>
<td>导出pngsvgpdf时在头部添加自定义内容可传递一个函数这个函数可以返回null代表不添加内容也可以返回一个对象详细介绍请参考下方导出时如何添加自定义内容</td>
</tr>
<tr>
<td>addContentToFooterv0.9.9+</td>
<td>Functionnull</td>
<td>null</td>
<td>基本释义同addContentToHeader在尾部添加自定义内容</td>
</tr>
<tr>
<td>demonstrateConfigv0.9.11+</td>
<td>Objectnull</td>
<td>null</td>
<td>演示插件Demonstrate的配置不传则使用默认配置可传递一个对象如果只配置某个属性可以只设置该属性其他没有设置的同样会使用默认配置完整配置请参考下方演示插件配置小节</td>
</tr>
<tr>
<td>resetScaleOnMoveNodeToCenterv0.9.12+</td>
<td>Boolean</td>
<td>false</td>
@@ -601,17 +440,17 @@
<td>createNodePrefixContentv0.9.12+</td>
<td>Functionnull</td>
<td>null</td>
<td>添加附加的节点前置内容前置内容指和文本同一行的区域中的前置内容不包括节点图片部分可以传递一个函数这个函数接收一个节点实例的参数可以返回一个DOM节点也可以返回null</td>
<td>添加附加的节点前置内容前置内容指和文本同一行的区域中的前置内容不包括节点图片部分可以传递一个函数这个函数接收一个节点实例的参数可以返回{el, width, height}格式的对象el为DOM节点对象width和height代表内容的宽高数字类型如果不需要自定义内容也可以返回null</td>
</tr>
<tr>
<td>createNodePostfixContentv0.9.12+</td>
<td>Functionnull</td>
<td>null</td>
<td>添加附加的节点后置内容后置内容指和文本同一行的区域中的后置内容不包括节点图片部分可以传递一个函数这个函数接收一个节点实例的参数可以返回一个DOM节点也可以返回null</td>
<td>添加附加的节点后置内容后置内容指和文本同一行的区域中的后置内容不包括节点图片部分用法同createNodePrefixContent</td>
</tr>
</tbody>
</table>
<h3>数据结构</h3>
<h4>1.1数据结构</h4>
<p>基本的数据结构如下</p>
<pre class="hljs"><code>{
<span class="hljs-attr">data</span>: {
@@ -651,7 +490,220 @@
}
</code></pre>
<p>如果你要添加自定义的字段可以添加到<code>data</code><code>children</code>同级如果你要添加到<code>data</code>对象里那么请使用<code>_</code>开头来命名你的自定义字段内部会通过这个来判断是否是自定义字段</p>
<h3>水印配置</h3>
<h4>1.2图标配置</h4>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td>
<td>String</td>
<td></td>
<td>图标分组的名称</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td></td>
<td>图标分组的值</td>
</tr>
<tr>
<td>list</td>
<td>Array</td>
<td></td>
<td>分组下的图标列表数组的每一项为一个对象<code>{ name: '', icon: '' }</code><code>name</code>代表图标的名称<code>icon</code>代表图标可以是<code>svg</code>图标比如<code>&lt;svg ...&gt;&lt;path&gt;&lt;/path&gt;&lt;/svg&gt;</code><code>url</code><code>base64</code><code>data:image/png;base64,...</code></td>
</tr>
</tbody>
</table>
<h3>2.Export插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>exportPadding已废除</td>
<td>Number</td>
<td>20</td>
<td>导出图片时的内边距</td>
</tr>
<tr>
<td>exportPaddingXv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>导出pngsvgpdf时的图形水平内边距</td>
</tr>
<tr>
<td>exportPaddingYv0.5.5+</td>
<td>Number</td>
<td>10</td>
<td>导出pngsvgpdf时的图形垂直内边距</td>
</tr>
<tr>
<td>resetCssv0.6.16+</td>
<td>String</td>
<td>* { margin: 0; padding: 0; box-sizing: border-box; }</td>
<td>设置导出图片和svg时针对富文本节点内容也就是嵌入到svg中的html节点的默认样式覆盖如果不覆盖节点内容会发生偏移</td>
</tr>
<tr>
<td>minExportImgCanvasScalev0.7.0+</td>
<td>Number</td>
<td>2</td>
<td>导出图片和pdf时canvas的缩放倍数该配置会和window.devicePixelRatio值取最大值用于提升图片清晰度</td>
</tr>
<tr>
<td>addContentToHeaderv0.9.9+</td>
<td>Functionnull</td>
<td>null</td>
<td>导出pngsvgpdf时在头部添加自定义内容可传递一个函数这个函数可以返回null代表不添加内容也可以返回一个对象详细介绍请参考下方导出时如何添加自定义内容</td>
</tr>
<tr>
<td>addContentToFooterv0.9.9+</td>
<td>Functionnull</td>
<td>null</td>
<td>基本释义同addContentToHeader在尾部添加自定义内容</td>
</tr>
</tbody>
</table>
<h4>2.1导出时如何添加自定义内容</h4>
<p><code>addContentToHeader</code><code>addContentToFooter</code>两个实例化选项可以用于在导出<code>png</code><code>svg</code><code>pdf</code>时在头部和尾部添加自定义的内容默认为<code>null</code>代表不配置可以传递一个函数函数可以返回<code>null</code>代表不添加内容如果要添加内容那么需要返回如下的结构</p>
<pre class="hljs"><code>{
el,// 要追加的自定义DOM节点样式可内联
cssText,// 可选如果样式不想内联可以传递该值一个css字符串
height: 50// 返回的DOM节点的高度必须传递
}
</code></pre>
<p>一个简单的示例</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-attr">addContentToFooter</span>: <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> el = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;div&#x27;</span>)
el.className = <span class="hljs-string">&#x27;footer&#x27;</span>
el.innerHTML = <span class="hljs-string">&#x27;来自simple-mind-map&#x27;</span>
<span class="hljs-keyword">const</span> cssText = <span class="hljs-string">`
.footer {
width: 100%;
height: 30px;
}
`</span>
<span class="hljs-keyword">return</span> {
el,
cssText,
<span class="hljs-attr">height</span>: <span class="hljs-number">30</span>
}
}
})
</code></pre>
<h3>3.Select插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>selectTranslateStep</td>
<td>Number</td>
<td>3</td>
<td>多选节点时鼠标移动到边缘时的画布移动偏移量</td>
</tr>
<tr>
<td>selectTranslateLimit</td>
<td>Number</td>
<td>20</td>
<td>多选节点时鼠标移动距边缘多少距离时开始偏移</td>
</tr>
</tbody>
</table>
<h3>4.Drag插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>enableFreeDragv0.2.4+</td>
<td>Boolean</td>
<td>false</td>
<td>是否开启节点自由拖拽自由拖拽即可以把节点拖拽到画布的任意位置注意不是拖拽节点成为其他节点的子节点兄弟节点的功能自由拖拽的连线会存在一定问题所以该特性最好不要使用</td>
</tr>
<tr>
<td>nodeDragPlaceholderMaxSizev0.6.12+v0.10.0+已废除</td>
<td>Number</td>
<td>20</td>
<td>拖拽元素时指示元素新位置的块的最大高度</td>
</tr>
<tr>
<td>autoMoveWhenMouseInEdgeOnDragv0.7.1+</td>
<td>Boolean</td>
<td>true</td>
<td>拖拽节点时鼠标移动到画布边缘是否开启画布自动移动</td>
</tr>
<tr>
<td>dragMultiNodeRectConfigv0.7.2+</td>
<td>Object</td>
<td>{ width: 40, height: 20, fill: 'rgb(94, 200, 248)' }</td>
<td>拖拽多个节点时随鼠标移动的示意矩形的样式配置传递一个对象字段含义分别为矩形的宽填充色</td>
</tr>
<tr>
<td>dragPlaceholderRectFillv0.7.2+</td>
<td>String</td>
<td>rgb(94, 200, 248)</td>
<td>节点拖拽时新位置的示意矩形的填充颜色</td>
</tr>
<tr>
<td>dragPlaceholderLineConfigv0.10.0+</td>
<td>Object</td>
<td>{ color: 'rgb(94, 200, 248)', width: 2 }</td>
<td>节点拖拽时新位置的示意连线的样式配置</td>
</tr>
<tr>
<td>dragOpacityConfigv0.7.2+</td>
<td>Object</td>
<td>{ cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 }</td>
<td>节点拖拽时的透明度配置传递一个对象字段含义分别为跟随鼠标移动的克隆节点或矩形的透明度被拖拽节点的透明度</td>
</tr>
</tbody>
</table>
<h3>5.Watermark插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>watermarkConfigv0.2.4+</td>
<td>Object</td>
<td></td>
<td>水印配置详细配置请参考下方表格水印配置</td>
</tr>
</tbody>
</table>
<h4>5.1水印配置</h4>
<table>
<thead>
<tr>
@@ -698,9 +750,15 @@
<td>false</td>
<td>是否仅在导出时添加水印</td>
</tr>
<tr>
<td>belowNodev0.10.0+</td>
<td>Boolean</td>
<td>false</td>
<td>水印是否显示在节点下方</td>
</tr>
</tbody>
</table>
<h3>图标配置</h3>
<h3>6.AssociativeLine插件</h3>
<table>
<thead>
<tr>
@@ -712,54 +770,183 @@
</thead>
<tbody>
<tr>
<td>name</td>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td></td>
<td>图标分组的名称</td>
<td>关联</td>
<td>关联线默认文字</td>
</tr>
<tr>
<td>type</td>
<td>String</td>
<td></td>
<td>图标分组的值</td>
<td>associativeLineIsAlwaysAboveNodev0.8.0+</td>
<td>Boolean</td>
<td>true</td>
<td>关联线是否始终显示在节点上层如果设为false那么创建关联线和激活关联线时处于最顶层其他情况下处于节点下方</td>
</tr>
<tr>
<td>list</td>
<td>Array</td>
<td></td>
<td>分组下的图标列表数组的每一项为一个对象<code>{ name: '', icon: '' }</code><code>name</code>代表图标的名称<code>icon</code>代表图标可以是<code>svg</code>图标比如<code>&lt;svg ...&gt;&lt;path&gt;&lt;/path&gt;&lt;/svg&gt;</code><code>url</code><code>base64</code><code>data:image/png;base64,...</code></td>
<td>associativeLineInitPointsPositionv0.9.5+</td>
<td>null / { from, to }</td>
<td>{ from: '', to: '' }</td>
<td>默认情况下新创建的关联线两个端点的位置是根据两个节点中心点的相对位置来计算的如果你想固定位置可以通过这个选项来配置from和to都不传则都自动计算如果只传一个另一个则会自动计算from和to可选值lefttopbottomright</td>
</tr>
<tr>
<td>enableAdjustAssociativeLinePointsv0.9.5+</td>
<td>Boolean</td>
<td>true</td>
<td>是否允许调整关联线两个端点的位置</td>
</tr>
</tbody>
</table>
<h3>导出时如何添加自定义内容</h3>
<p><code>addContentToHeader</code><code>addContentToFooter</code>两个实例化选项可以用于在导出<code>png</code><code>svg</code><code>pdf</code>时在头部和尾部添加自定义的内容默认为<code>null</code>代表不配置可以传递一个函数函数可以返回<code>null</code>代表不添加内容如果要添加内容那么需要返回如下的结构</p>
<pre class="hljs"><code>{
el,// 要追加的自定义DOM节点样式可内联
cssText,// 可选如果样式不想内联可以传递该值一个css字符串
height: 50// 返回的DOM节点的高度必须传递
}
</code></pre>
<p>一个简单的示例</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-attr">addContentToFooter</span>: <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> el = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">&#x27;div&#x27;</span>)
el.className = <span class="hljs-string">&#x27;footer&#x27;</span>
el.innerHTML = <span class="hljs-string">&#x27;来自simple-mind-map&#x27;</span>
<span class="hljs-keyword">const</span> cssText = <span class="hljs-string">`
.footer {
width: 100%;
height: 30px;
}
`</span>
<span class="hljs-keyword">return</span> {
el,
cssText,
<span class="hljs-attr">height</span>: <span class="hljs-number">30</span>
}
}
})
</code></pre>
<h3>演示插件配置</h3>
<h3>7.RichText插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>richTextEditFakeInPlacev0.6.13+</td>
<td>Boolean</td>
<td>false</td>
<td>设置富文本节点编辑框和节点大小一致形成伪原地编辑的效果需要注意的是只有当节点内只有文本且形状是矩形才会有比较好的效果</td>
</tr>
<tr>
<td>enableEditFormulaInRichTextEditv0.10.0+</td>
<td>Boolean</td>
<td>true</td>
<td>是否开启在富文本编辑框中直接编辑数学公式</td>
</tr>
<tr>
<td>transformRichTextOnEnterEditv0.10.0+</td>
<td>nullFunction</td>
<td>null</td>
<td>转换富文本内容可以传递一个函数当进入富文本编辑时会调用该函数函数接收即将被编辑的富文本内容需要返回你处理后的富文本内容</td>
</tr>
<tr>
<td>beforeHideRichTextEditv0.10.0+</td>
<td>nullFunction</td>
<td>null</td>
<td>可以传递一个函数即将结束富文本编辑前会执行该函数函数接收richText实例所以你可以在此时机更新quill文档数据</td>
</tr>
</tbody>
</table>
<h3>8.TouchEvent插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>disableTouchZoomv0.8.1+</td>
<td>Boolean</td>
<td>false</td>
<td>禁止双指缩放你仍旧可以使用api进行缩放对TouchEvent插件生效</td>
</tr>
</tbody>
</table>
<h3>9.Scrollbar插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+</td>
<td>Boolean</td>
<td>true</td>
<td>当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas配置不再起作用</td>
</tr>
</tbody>
</table>
<h3>10.Search插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>isOnlySearchCurrentRenderNodesv0.9.8+</td>
<td>Boolean</td>
<td>false</td>
<td>是否仅搜索当前渲染的节点被收起的节点不会被搜索到</td>
</tr>
</tbody>
</table>
<h3>11.Cooperate插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>beforeCooperateUpdatev0.9.8+</td>
<td>Functionnull</td>
<td>null</td>
<td>协同编辑时节点操作即将更新到其他客户端前的生命周期函数函数接收一个对象作为参数{ type: createOrUpdate创建节点或更新节点delete删除节点, list: 数组类型1.当type=createOrUpdate时代表被创建或被更新的节点数据即将同步到其他客户端所以你可以修改该数据2.当type=delete时代表被删除的节点数据 }</td>
</tr>
</tbody>
</table>
<h3>12.RainbowLines插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>rainbowLinesConfigv0.9.9+</td>
<td>Object</td>
<td>{ open: false, colorsList: [] }</td>
<td>彩虹线条配置需要先注册RainbowLines插件对象类型结构{ open: false是否开启彩虹线条, colorsList: []自定义彩虹线条的颜色列表如果不设置会使用默认颜色列表 }</td>
</tr>
</tbody>
</table>
<h3>13.Demonstrate插件</h3>
<table>
<thead>
<tr>
<th>字段名称</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>demonstrateConfigv0.9.11+</td>
<td>Objectnull</td>
<td>null</td>
<td>演示插件Demonstrate的配置不传则使用默认配置可传递一个对象如果只配置某个属性可以只设置该属性其他没有设置的同样会使用默认配置完整配置请参考下方演示插件配置小节</td>
</tr>
</tbody>
</table>
<h4>13.1演示插件配置</h4>
<table>
<thead>
<tr>
@@ -1129,6 +1316,11 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<td></td>
</tr>
<tr>
<td>node_tree_render_startv0.10.0+</td>
<td>节点树开始渲染事件</td>
<td></td>
</tr>
<tr>
<td>rich_text_selection_changev0.4.0+</td>
<td>当注册了<code>RichText</code>插件时可用当节点编辑时文本选区发生改变时触发</td>
<td>hasRange是否存在选区rectInfo选区的尺寸和位置信息formatInfo选区的文本格式化信息</td>

View File

@@ -0,0 +1,82 @@
# 局域网docker部署解决HTTPS问题的一种方法
> 本文来自:[Brzjomo](https://github.com/Brzjomo)的[issue](https://github.com/wanglin2/mind-map/issues/658)。
受Api的限制MindMap以HTTP访问时目录、新建和打开功能不能正常工作。因此在局域网架设时需要给它进行配置证书等操作使其正常工作。
假设先前已经基于Github源码架设了MindMap的docker服务。没有的先看这个[Issue](https://github.com/wanglin2/mind-map/issues/309)
事前准备:
需要准备一个域名。
需要安装Linux 服务器运维管理面板[1panel](https://github.com/1Panel-dev/1Panel)
设置域名解析:
以阿里云为例,登录后进入[域名解析页面](https://dns.console.aliyun.com/#/dns/domainList)
点击对应域名的解析设置。
添加或编辑对应的@和www记录将IP记录值修改为局域网IP比如192.168.2.36。
保存后退出。
获取AccessKey
进入账号下面的AccessKey管理。
创建或者使用已经记录的AccessKey。
1panel设置
进入应用商店安装OpenResty稍后用于申请证书和设置反代
进入网站-网站,点击创建网站。
点击反向代理。
设置主域名为自己的域名。
代理地址为http和127.0.0.1:MindMap容器端口。
点击确认。
创建证书申请账户:
进入1panel的网站-证书点击Acme 账户。
点击创建账户。
输入邮箱后确认。
回到刚才的证书页面点击DNS 账户。
点击创建账户。
填写名称后选择类型为阿里云DNS。
再填入刚才准备好的Access Key和Secret Key。
点击确认。
申请证书:
回到刚才的证书页面,点击申请证书。
填写主域名,其他按实际情况填写。一般会自动设置。
点击确认,等待其成功。
启用HTTPS访问
回到1panel的网站管理页面。
找到刚才建立的反向代理,点击配置。
点击HTTPS。
点击启用HTTPS。
SSL 选项设置为选择已有证书。
选择好刚才创建的Acme账户和证书。
点击保存。
此时在局域网内访问该域名应当能正确以Https访问MindMap了。
如果不能输入host 域名查看返回的DNS解析是否为局域网IP。

View File

@@ -0,0 +1,62 @@
<template>
<div>
<h1>局域网docker部署解决HTTPS问题的一种方法</h1>
<blockquote>
<p>本文来自<a href="https://github.com/Brzjomo">Brzjomo</a><a href="https://github.com/wanglin2/mind-map/issues/658">issue</a></p>
</blockquote>
<p>受Api的限制MindMap以HTTP访问时目录新建和打开功能不能正常工作因此在局域网架设时需要给它进行配置证书等操作使其正常工作</p>
<p>假设先前已经基于Github源码架设了MindMap的docker服务没有的先看这个<a href="https://github.com/wanglin2/mind-map/issues/309">Issue</a></p>
<p>事前准备
需要准备一个域名</p>
<p>需要安装Linux 服务器运维管理面板<a href="https://github.com/1Panel-dev/1Panel">1panel</a></p>
<p>设置域名解析
以阿里云为例登录后进入<a href="https://dns.console.aliyun.com/#/dns/domainList">域名解析页面</a></p>
<p>点击对应域名的解析设置</p>
<p>添加或编辑对应的@和www记录将IP记录值修改为局域网IP比如192.168.2.36</p>
<p>保存后退出</p>
<p>获取AccessKey
进入账号下面的AccessKey管理</p>
<p>创建或者使用已经记录的AccessKey</p>
<p>1panel设置
进入应用商店安装OpenResty稍后用于申请证书和设置反代</p>
<p>进入网站-网站点击创建网站</p>
<p>点击反向代理</p>
<p>设置主域名为自己的域名</p>
<p>代理地址为http和127.0.0.1:MindMap容器端口</p>
<p>点击确认</p>
<p>创建证书申请账户
进入1panel的网站-证书点击Acme 账户</p>
<p>点击创建账户</p>
<p>输入邮箱后确认</p>
<p>回到刚才的证书页面点击DNS 账户</p>
<p>点击创建账户</p>
<p>填写名称后选择类型为阿里云DNS</p>
<p>再填入刚才准备好的Access Key和Secret Key</p>
<p>点击确认</p>
<p>申请证书
回到刚才的证书页面点击申请证书</p>
<p>填写主域名其他按实际情况填写一般会自动设置</p>
<p>点击确认等待其成功</p>
<p>启用HTTPS访问
回到1panel的网站管理页面</p>
<p>找到刚才建立的反向代理点击配置</p>
<p>点击HTTPS</p>
<p>点击启用HTTPS</p>
<p>SSL 选项设置为选择已有证书</p>
<p>选择好刚才创建的Acme账户和证书</p>
<p>点击保存</p>
<p>此时在局域网内访问该域名应当能正确以Https访问MindMap了</p>
<p>如果不能输入host 域名查看返回的DNS解析是否为局域网IP</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -0,0 +1,9 @@
# 如何编辑数学公式
数学公式只在开启了【富文本】编辑模式下才可使用。
首先可以激活节点,然后点击上方工具栏中的【公式】打开右侧的格式侧边栏,然后再输入框中输入公式后点击【完成】即可将公式输入节点。
当你再次双击节点时,公式会转换成源码,你可以直接修改,回车完成后即可渲染。
所以你也可以不通过侧边栏,直接在文本编辑框中输入公式,不过公式的源码前后必须通过`$`符号包裹,否则不会解析为格式。

View File

@@ -0,0 +1,20 @@
<template>
<div>
<h1>如何编辑数学公式</h1>
<p>数学公式只在开启了富文本编辑模式下才可使用</p>
<p>首先可以激活节点然后点击上方工具栏中的公式打开右侧的格式侧边栏然后再输入框中输入公式后点击完成即可将公式输入节点</p>
<p>当你再次双击节点时公式会转换成源码你可以直接修改回车完成后即可渲染</p>
<p>所以你也可以不通过侧边栏直接在文本编辑框中输入公式不过公式的源码前后必须通过<code>$</code>符号包裹否则不会解析为格式</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -380,7 +380,7 @@
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/孟照星.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>孟照星</p>
<p>Alex</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/子豪.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
@@ -390,4 +390,20 @@
<img src="../../../../assets/avatar/宏涛.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>宏涛</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/最多5个字.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>最多5个字</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/雨馨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>雨馨</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/ZX.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>ZX</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/峰.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>峰</p>
</div>
</div>

View File

@@ -8,18 +8,18 @@
</blockquote>
<h2>特性</h2>
<ul>
<li><input type="checkbox" id="checkbox235" checked="true" /><label for="checkbox235">插件化架构除核心功能外其他功能作为插件提供按需使用减小打包体积</label></li>
<li><input type="checkbox" id="checkbox236" checked="true" /><label for="checkbox236">支持逻辑结构图思维导图组织结构图目录组织图时间轴横向竖向鱼骨图等结构</label></li>
<li><input type="checkbox" id="checkbox237" checked="true" /><label for="checkbox237">内置多种主题允许高度自定义样式支持注册新主题</label></li>
<li><input type="checkbox" id="checkbox238" checked="true" /><label for="checkbox238">节点内容支持文本普通文本富文本图片图标超链接备注标签概要数学公式</label></li>
<li><input type="checkbox" id="checkbox239" checked="true" /><label for="checkbox239">节点支持拖拽拖拽移动自由调整多种节点形状支持扩展节点内容支持使用 DDM 完全自定义节点内容</label></li>
<li><input type="checkbox" id="checkbox240" checked="true" /><label for="checkbox240">支持画布拖动缩放</label></li>
<li><input type="checkbox" id="checkbox241" checked="true" /><label for="checkbox241">支持鼠标按键拖动选择和 Ctrl+左键两种多选节点方式</label></li>
<li><input type="checkbox" id="checkbox242" checked="true" /><label for="checkbox242">支持导出为</label><code>json</code><code>png</code><code>svg</code><code>pdf</code><code>markdown</code><code>xmind</code><code>txt</code>支持从<code>json</code><code>xmind</code><code>markdown</code>导入</li>
<li><input type="checkbox" id="checkbox243" checked="true" /><label for="checkbox243">支持快捷键前进后退关联线搜索替换小地图水印滚动条手绘风格彩虹线条</label></li>
<li><input type="checkbox" id="checkbox244" checked="true" /><label for="checkbox244">提供丰富的配置满足各种场景各种使用习惯</label></li>
<li><input type="checkbox" id="checkbox245" checked="true" /><label for="checkbox245">支持协同编辑</label></li>
<li><input type="checkbox" id="checkbox246" checked="true" /><label for="checkbox246">支持演示模式</label></li>
<li><input type="checkbox" id="checkbox0" checked="true" /><label for="checkbox0">插件化架构除核心功能外其他功能作为插件提供按需使用减小打包体积</label></li>
<li><input type="checkbox" id="checkbox1" checked="true" /><label for="checkbox1">支持逻辑结构图思维导图组织结构图目录组织图时间轴横向竖向鱼骨图等结构</label></li>
<li><input type="checkbox" id="checkbox2" checked="true" /><label for="checkbox2">内置多种主题允许高度自定义样式支持注册新主题</label></li>
<li><input type="checkbox" id="checkbox3" checked="true" /><label for="checkbox3">节点内容支持文本普通文本富文本图片图标超链接备注标签概要数学公式</label></li>
<li><input type="checkbox" id="checkbox4" checked="true" /><label for="checkbox4">节点支持拖拽拖拽移动自由调整多种节点形状支持扩展节点内容支持使用 DDM 完全自定义节点内容</label></li>
<li><input type="checkbox" id="checkbox5" checked="true" /><label for="checkbox5">支持画布拖动缩放</label></li>
<li><input type="checkbox" id="checkbox6" checked="true" /><label for="checkbox6">支持鼠标按键拖动选择和 Ctrl+左键两种多选节点方式</label></li>
<li><input type="checkbox" id="checkbox7" checked="true" /><label for="checkbox7">支持导出为</label><code>json</code><code>png</code><code>svg</code><code>pdf</code><code>markdown</code><code>xmind</code><code>txt</code>支持从<code>json</code><code>xmind</code><code>markdown</code>导入</li>
<li><input type="checkbox" id="checkbox8" checked="true" /><label for="checkbox8">支持快捷键前进后退关联线搜索替换小地图水印滚动条手绘风格彩虹线条</label></li>
<li><input type="checkbox" id="checkbox9" checked="true" /><label for="checkbox9">提供丰富的配置满足各种场景各种使用习惯</label></li>
<li><input type="checkbox" id="checkbox10" checked="true" /><label for="checkbox10">支持协同编辑</label></li>
<li><input type="checkbox" id="checkbox11" checked="true" /><label for="checkbox11">支持演示模式</label></li>
</ul>
<p>官方提供了如下插件可根据需求按需引入某个功能不生效大概率是因为你没有引入对应的插件具体使用方式请查看文档</p>
<blockquote>
@@ -37,11 +37,11 @@
<p>2.<code>web</code></p>
<p>使用<code>simple-mind-map</code>基于<code>vue2.x</code><code>ElementUI</code>搭建的在线思维导图特性</p>
<ul>
<li><input type="checkbox" id="checkbox247" checked="true" /><label for="checkbox247">工具栏支持插入节点删除节点编辑节点图片图标超链接备注标签概要</label></li>
<li><input type="checkbox" id="checkbox248" checked="true" /><label for="checkbox248">侧边栏基础样式设置面板节点样式设置面板大纲面板主题选择面板结构选择面板</label></li>
<li><input type="checkbox" id="checkbox249" checked="true" /><label for="checkbox249">导入导出功能数据默认保存在浏览器本地存储也支持直接创建打开编辑电脑本地文件</label></li>
<li><input type="checkbox" id="checkbox250" checked="true" /><label for="checkbox250">右键菜单支持展开收起整理布局等操作</label></li>
<li><input type="checkbox" id="checkbox251" checked="true" /><label for="checkbox251">底部栏支持节点数量字数统计支持切换编辑和只读模式支持放大缩小支持全屏切换支持小地图</label></li>
<li><input type="checkbox" id="checkbox12" checked="true" /><label for="checkbox12">工具栏支持插入节点删除节点编辑节点图片图标超链接备注标签概要</label></li>
<li><input type="checkbox" id="checkbox13" checked="true" /><label for="checkbox13">侧边栏基础样式设置面板节点样式设置面板大纲面板主题选择面板结构选择面板</label></li>
<li><input type="checkbox" id="checkbox14" checked="true" /><label for="checkbox14">导入导出功能数据默认保存在浏览器本地存储也支持直接创建打开编辑电脑本地文件</label></li>
<li><input type="checkbox" id="checkbox15" checked="true" /><label for="checkbox15">右键菜单支持展开收起整理布局等操作</label></li>
<li><input type="checkbox" id="checkbox16" checked="true" /><label for="checkbox16">底部栏支持节点数量字数统计支持切换编辑和只读模式支持放大缩小支持全屏切换支持小地图</label></li>
</ul>
<p>提供文档页面服务</p>
<p>3.<code>dist</code></p>
@@ -331,7 +331,7 @@
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/孟照星.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>孟照星</p>
<p>Alex</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/子豪.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
@@ -341,6 +341,22 @@
<img src="../../../../assets/avatar/宏涛.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>宏涛</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/最多5个字.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>最多5个字</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/雨馨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>雨馨</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/ZX.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>ZX</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/峰.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p></p>
</div>
</div>
</div>
</template>

View File

@@ -511,6 +511,16 @@ document.addEventListener(fullscrrenEvent, () => {
退出全屏状态。
#### defenseXSS(htmlStr)
> v0.10.0+
- `htmlStr`需要过滤的html字符串
返回过滤后的html字符串
防御 XSS 攻击,过滤恶意 HTML 标签和属性。你可以在将节点数据传递给SimpleMindMap前递归遍历树数据通过该方法处理节点富文本内容避免 XSS 攻击。
## 在 canvas 中模拟 css 的背景属性
引入:

View File

@@ -427,6 +427,15 @@
<p>v0.9.11+</p>
</blockquote>
<p>退出全屏状态</p>
<h4>defenseXSS(htmlStr)</h4>
<blockquote>
<p>v0.10.0+</p>
</blockquote>
<ul>
<li><code>htmlStr</code>需要过滤的html字符串</li>
</ul>
<p>返回过滤后的html字符串</p>
<p>防御 XSS 攻击过滤恶意 HTML 标签和属性你可以在将节点数据传递给SimpleMindMap前递归遍历树数据通过该方法处理节点富文本内容避免 XSS 攻击</p>
<h2> canvas 中模拟 css 的背景属性</h2>
<p>引入</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils/simulateCSSBackgroundInCanvas&#x27;</span>

View File

@@ -22,12 +22,14 @@ simpleMindMap.xmind
## 方法
### xmind.parseXmindFile(file)
### xmind.parseXmindFile(file, handleMultiCanvas)
解析`.xmind`文件,返回解析后的数据,可以使用`mindMap.setData(data)`来将返回的数据渲染到画布上
`file``File`对象
`handleMultiCanvas`v0.10.0+可选可传递一个函数如果导入的xmind文件存在多个画布那么会调用该函数函数接收xmind画布列表数据为参数需要返回其中一个画布的数据比如接收的参数为`content`,要导入第二个画布的数据则返回`content[1]`。函数可以是异步函数返回一个Promise实例。
### xmind.transformXmind(content)
> v0.6.6+版本该方法改为异步方法返回一个Promise实例

View File

@@ -14,9 +14,10 @@
<pre class="hljs"><code>simpleMindMap.xmind
</code></pre>
<h2>方法</h2>
<h3>xmind.parseXmindFile(file)</h3>
<h3>xmind.parseXmindFile(file, handleMultiCanvas)</h3>
<p>解析<code>.xmind</code>文件返回解析后的数据可以使用<code>mindMap.setData(data)</code>来将返回的数据渲染到画布上</p>
<p><code>file</code><code>File</code>对象</p>
<p><code>handleMultiCanvas</code>v0.10.0+可选可传递一个函数如果导入的xmind文件存在多个画布那么会调用该函数函数接收xmind画布列表数据为参数需要返回其中一个画布的数据比如接收的参数为<code>content</code>要导入第二个画布的数据则返回<code>content[1]</code>函数可以是异步函数返回一个Promise实例</p>
<h3>xmind.transformXmind(content)</h3>
<blockquote>
<p>v0.6.6+版本该方法改为异步方法返回一个Promise实例</p>

View File

@@ -696,6 +696,16 @@
>
</div>
</div>
<!-- 是否在节点下方 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.belowNode"
@change="updateWatermarkConfig"
>{{ $t('baseStyle.belowNode') }}</el-checkbox
>
</div>
</div>
<!-- 水印文字 -->
<div class="row">
<div class="rowItem">

View File

@@ -12,8 +12,7 @@
</template>
<script>
import {mapState} from 'vuex'
import {defenseXSS} from 'simple-mind-map/src/utils/xss'
import { mapState } from 'vuex'
/**
* @Author: 王林
@@ -39,7 +38,7 @@ export default {
computed: {
...mapState({
isDark: state => state.localConfig.isDark
}),
})
},
created() {
this.$bus.$on('data_change', this.onDataChange)
@@ -61,7 +60,7 @@ export default {
this.words = 0
this.num = 0
this.walk(data)
countEl.innerHTML = defenseXSS(this.textStr)
countEl.innerHTML = this.textStr
this.words = countEl.textContent.length
},
@@ -102,7 +101,7 @@ export default {
background: #262a2e;
.item {
color: hsla(0, 0%, 100%, .6);
color: hsla(0, 0%, 100%, 0.6);
}
}

View File

@@ -1,36 +1,56 @@
<template>
<el-dialog
class="nodeImportDialog"
:title="$t('import.title')"
:visible.sync="dialogVisible"
width="300px"
>
<el-upload
ref="upload"
action="x"
accept=".smm,.json,.xmind,.xlsx,.md"
:file-list="fileList"
:auto-upload="false"
:multiple="false"
:on-change="onChange"
:on-remove="onRemove"
:limit="1"
:on-exceed="onExceed"
<div>
<el-dialog
class="nodeImportDialog"
:title="$t('import.title')"
:visible.sync="dialogVisible"
width="300px"
>
<el-button slot="trigger" size="small" type="primary">{{
$t('import.selectFile')
}}</el-button>
<div slot="tip" class="el-upload__tip">
{{ $t('import.supportFile') }}
</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
<el-button type="primary" @click="confirm">{{
$t('dialog.confirm')
}}</el-button>
</span>
</el-dialog>
<el-upload
ref="upload"
action="x"
accept=".smm,.json,.xmind,.xlsx,.md"
:file-list="fileList"
:auto-upload="false"
:multiple="false"
:on-change="onChange"
:on-remove="onRemove"
:limit="1"
:on-exceed="onExceed"
>
<el-button slot="trigger" size="small" type="primary">{{
$t('import.selectFile')
}}</el-button>
<div slot="tip" class="el-upload__tip">
{{ $t('import.supportFile') }}
</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
<el-button type="primary" @click="confirm">{{
$t('dialog.confirm')
}}</el-button>
</span>
</el-dialog>
<el-dialog
class="xmindCanvasSelectDialog"
:title="$t('import.xmindCanvasSelectDialogTitle')"
:visible.sync="xmindCanvasSelectDialogVisible"
width="300px"
:show-close="false"
>
<el-radio-group v-model="selectCanvas" class="canvasList">
<el-radio v-for="(item, index) in canvasList" :key="index" :label="index">{{
item.title
}}</el-radio>
</el-radio-group>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmSelect">{{
$t('dialog.confirm')
}}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
@@ -50,7 +70,11 @@ export default {
data() {
return {
dialogVisible: false,
fileList: []
fileList: [],
selectPromiseResolve: null,
xmindCanvasSelectDialogVisible: false,
selectCanvas: '',
canvasList: []
}
},
watch: {
@@ -106,11 +130,7 @@ export default {
}
},
/**
* @Author: 王林
* @Date: 2021-08-03 22:48:42
* @Desc: 文件选择
*/
// 文件选择
onChange(file) {
let reg = /\.(smm|xmind|json|xlsx|md)$/
if (!reg.test(file.name)) {
@@ -126,29 +146,17 @@ export default {
this.fileList = fileList
},
/**
* @Author: 王林
* @Date: 2021-08-03 22:48:47
* @Desc: 数量超出限制
*/
// 数量超出限制
onExceed() {
this.$message.error(this.$t('import.maxFileNum'))
},
/**
* @Author: 王林
* @Date: 2021-06-22 22:08:11
* @Desc: 取消
*/
// 取消
cancel() {
this.dialogVisible = false
},
/**
* @Author: 王林
* @Date: 2021-06-06 22:28:20
* @Desc: 确定
*/
// 确定
confirm() {
if (this.fileList.length <= 0) {
return this.$message.error(this.$t('import.notSelectTip'))
@@ -168,11 +176,7 @@ export default {
this.setActiveSidebar(null)
},
/**
* @Author: 王林25
* @Date: 2022-10-24 14:19:33
* @Desc: 处理.smm文件
*/
// 处理.smm文件
handleSmm(file) {
let fileReader = new FileReader()
fileReader.readAsText(file.raw)
@@ -191,14 +195,15 @@ export default {
}
},
/**
* @Author: 王林25
* @Date: 2022-10-24 14:19:41
* @Desc: 处理.xmind文件
*/
// 处理.xmind文件
async handleXmind(file) {
try {
let data = await xmind.parseXmindFile(file.raw)
let data = await xmind.parseXmindFile(file.raw, content => {
this.showSelectXmindCanvasDialog(content)
return new Promise(resolve => {
this.selectPromiseResolve = resolve
})
})
this.$bus.$emit('setData', data)
this.$message.success(this.$t('import.importSuccess'))
} catch (error) {
@@ -207,11 +212,22 @@ export default {
}
},
/**
* @Author: 王林25
* @Date: 2022-10-24 14:19:51
* @Desc: 处理.xlsx文件
*/
// 显示xmind文件的多个画布选择弹窗
showSelectXmindCanvasDialog(content) {
this.canvasList = content
this.selectCanvas = 0
this.xmindCanvasSelectDialogVisible = true
},
// 确认导入指定的画布
confirmSelect() {
this.selectPromiseResolve(this.canvasList[this.selectCanvas])
this.xmindCanvasSelectDialogVisible = false
this.canvasList = []
this.selectCanvas = 0
},
// 处理.xlsx文件
async handleExcel(file) {
try {
const wb = read(await fileToBuffer(file.raw))
@@ -306,4 +322,17 @@ export default {
<style lang="less" scoped>
.nodeImportDialog {
}
.canvasList {
display: flex;
flex-direction: column;
/deep/ .el-radio {
margin-bottom: 12px;
&:last-of-type {
margin-bottom: 0;
}
}
}
</style>

View File

@@ -70,7 +70,10 @@
class="fontOptionItem"
v-for="item in fontSizeList"
:key="item"
:style="{ fontSize: item + 'px' }"
:style="{
fontSize: item + 'px',
height: (item < 30 ? 30 : item + 10) + 'px'
}"
:class="{ active: formatInfo.size === item + 'px' }"
@click="changeFontSize(item)"
>

View File

@@ -30,14 +30,26 @@
<span class="icon iconfont icondakai"></span>
<span class="text">{{ $t('toolbar.directory') }}</span>
</div>
<div class="toolbarBtn" @click="createNewLocalFile">
<span class="icon iconfont iconxinjian"></span>
<span class="text">{{ $t('toolbar.newFile') }}</span>
</div>
<div class="toolbarBtn" @click="openLocalFile">
<span class="icon iconfont iconwenjian1"></span>
<span class="text">{{ $t('toolbar.openFile') }}</span>
</div>
<el-tooltip
effect="dark"
:content="$t('toolbar.newFileTip')"
placement="bottom"
>
<div class="toolbarBtn" @click="createNewLocalFile">
<span class="icon iconfont iconxinjian"></span>
<span class="text">{{ $t('toolbar.newFile') }}</span>
</div>
</el-tooltip>
<el-tooltip
effect="dark"
:content="$t('toolbar.openFileTip')"
placement="bottom"
>
<div class="toolbarBtn" @click="openLocalFile">
<span class="icon iconfont iconwenjian1"></span>
<span class="text">{{ $t('toolbar.openFile') }}</span>
</div>
</el-tooltip>
<div class="toolbarBtn" @click="saveLocalFile">
<span class="icon iconfont iconlingcunwei"></span>
<span class="text">{{ $t('toolbar.saveAs') }}</span>

View File

@@ -42,11 +42,11 @@ export default {
dataList: [
{
icon: 'iconstar',
value: 'Github star数量3000+'
value: 'Github star数量4000+'
},
{
icon: 'iconfork',
value: 'Github fork数量400+'
value: 'Github fork数量500+'
},
{
icon: 'iconxiazai',
@@ -54,7 +54,7 @@ export default {
},
{
icon: 'iconteamwork',
value: '代码贡献者16+'
value: '代码贡献者17+'
}
],
functionList: [