Compare commits

...

40 Commits

Author SHA1 Message Date
街角小林
6d378ca2e5 打包0.9.2 2023-12-26 18:33:29 +08:00
街角小林
5739fae4f7 Doc: update 2023-12-26 18:26:45 +08:00
街角小林
06ad8cfbf6 Feat:最大历史记录数量默认调整为500 2023-12-26 17:18:45 +08:00
街角小林
aed8e24afc Fix:修复节点数量过多,画布尺寸过大无法导出png和pdf的问题 2023-12-26 12:20:12 +08:00
街角小林
b7cb52b703 Fix:修复node_dragging事件回参里没有node实例的问题 2023-12-26 11:50:00 +08:00
街角小林
d4fc37fc98 Merge branch 'feature' of https://github.com/wanglin2/mind-map into feature 2023-12-26 10:23:46 +08:00
街角小林
7b4bd6b0bb Demo:基础样式配置连线支持显示箭头 2023-12-26 10:23:37 +08:00
街角小林
80f8a357fe Feat:节点连线支持显示箭头 2023-12-26 10:23:15 +08:00
wanglin2
a66cced73c Feat:去除导出pdf的特别处理 2023-12-25 20:50:50 +08:00
街角小林
29c5075fa5 Feat:重构pdf的导出逻辑,导出的pdf尺寸不再是固定的a4,而是思维导图的尺寸,同时取出分页导出的配置 2023-12-25 19:16:44 +08:00
街角小林
5bea2606f6 Fix:修复节点富文本编辑时,文本选中范围为null时没有触发rich_text_selection_change事件的问题 2023-12-25 18:10:51 +08:00
街角小林
9db988e3ec Fix:修复节点文本编辑状态中鼠标选择文本时移除编辑框,文字选中状态会丢失的问题 2023-12-25 18:09:25 +08:00
街角小林
bac174c8df Feat:新增自定义节点粘贴图片时的处理函数选项 2023-12-25 17:39:51 +08:00
街角小林
c0db185ca6 Doc: update 2023-12-25 17:25:37 +08:00
街角小林
642f486841 Doc: update 2023-12-25 17:25:17 +08:00
街角小林
69a97d44bc Fix:修复插入格式报错的问题 2023-12-25 16:30:29 +08:00
街角小林
d19fd7e186 Demo:支持配置仅在导出时显示水印 2023-12-25 10:13:13 +08:00
街角小林
2bcf763ea2 Feat:支持仅在导出时显示水印的配置选项 2023-12-25 10:12:43 +08:00
街角小林
9ea36a852f Fix:修复当节点数量比较多时,导出的图片中水印没有完全覆盖整个图片的问题 2023-12-25 09:36:06 +08:00
街角小林
4d2665c98b 优化部分插件代码,增加解绑事件的逻辑 2023-12-21 17:06:40 +08:00
街角小林
33a2e20ee2 Doc: update 2023-12-21 16:27:48 +08:00
街角小林
7b8946bec4 Demo:显示和移除滚动条时同时进行滚动条插件的注册和移除 2023-12-21 12:09:10 +08:00
街角小林
88f2e60720 Feat:收起所有节点操作将思维导图移至画布中心 2023-12-21 12:03:30 +08:00
街角小林
b4e0ad6881 Feat:支持配置注册了滚动条插件的情况下是否限制将思维导图限制在画布内 2023-12-21 12:01:00 +08:00
街角小林
d80ee1e7c8 Fix:修复当画布容器距浏览器窗口左上角不为0时,fit方法计算出来的位置有误差的问题 2023-12-21 11:25:08 +08:00
街角小林
3d0b257325 Feat:新增将思维导图图形限制在画布内的配置选项 2023-12-21 11:24:24 +08:00
街角小林
4d9aa1d3c2 Fix:修复拖拽画布时鼠标在节点上面松开时拖拽无法停止的问题 2023-12-21 10:32:45 +08:00
街角小林
abc30da43b Fix:修复滚动条插件在initRootNodePosition配置不为默认的center,center时位置计算错误的问题 2023-12-19 09:41:43 +08:00
街角小林
f887b14d1f Doc: update 2023-12-18 10:47:14 +08:00
街角小林
346e5b4ac8 Feat:render实例的paste方法改为支持粘贴剪贴板的数据 2023-12-18 10:35:19 +08:00
街角小林
6f7bb40c49 Fix:修复节点被销毁时鼠标移入标志没有复位的问题 2023-12-18 09:20:03 +08:00
街角小林
f3694d0c00 Merge branch 'feature' of https://github.com/wanglin2/mind-map into feature 2023-12-18 09:12:24 +08:00
街角小林
f2fbde3763 Doc: update 2023-12-18 09:12:15 +08:00
街角小林
b950c2bfe9 textEdit类增加isShowTextEdit方法判断当前是否处在节点编辑状态 2023-12-18 09:12:04 +08:00
wanglin2
69a7deedd7 Feat:修改mousewheel事件,dir标志修改为dirs,支持存储多个方向,优化触控板的双指移动操作 2023-12-17 21:32:13 +08:00
wanglin2
63b04e5acc Fix:修复鼠标或触控板水平滚动时画布移动方向相反的问题 2023-12-17 20:56:41 +08:00
街角小林
4a2816fc75 Fix:修复当节点数量超出了缓存池的最大数量时,前进回退会导致节点重复渲染的问题 2023-12-15 11:46:41 +08:00
街角小林
42ffbd728c Feat:优化reRender方法 2023-12-15 09:29:41 +08:00
街角小林
0ec16bd136 Feat:修复导入含有和当前画布已有节点uid相同的文件时会重复绘制节点的问题 2023-12-14 17:17:25 +08:00
街角小林
d517ee338f Fix:修复节点文本含有连续的数字或字母时没有换行的问题 2023-12-14 08:49:13 +08:00
135 changed files with 1796 additions and 767 deletions

View File

@@ -238,4 +238,8 @@ const mindMap = new MindMap({
<img src="./web/src/assets/avatar/HaHN.jpg" style="width: 50px;height: 50px;" />
<span>HaHN</span>
</span>
<span>
<img src="./web/src/assets/avatar/继龙.jpg" style="width: 50px;height: 50px;" />
<span>继龙</span>
</span>
</p>

File diff suppressed because one or more lines are too long

BIN
dist/img/继龙.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 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

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0abe0f"],{"16c7":function(t,e,o){"use strict";o.r(e);var a=function(){var t=this;t._self._c;return t._m(0)},n=[function(){var t=this,e=t._self._c;return e("div",[e("h1",[t._v("View instance")]),e("p",[t._v("The "),e("code",[t._v("view")]),t._v(" instance is responsible for view operations, and can be obtained through "),e("code",[t._v("mindMap.view")])]),e("h2",[t._v("Methods")]),e("h3",[t._v("fit()")]),e("blockquote",[e("p",[t._v("v0.6.0+")])]),e("p",[t._v("Zoom the mind map to fit the canvas.")]),e("h3",[t._v("translateX(step)")]),e("p",[t._v("Translate in the "),e("code",[t._v("x")]),t._v(" direction, "),e("code",[t._v("step")]),t._v(": number of pixels to translate")]),e("h3",[t._v("translateY(step)")]),e("p",[t._v("Translate in the "),e("code",[t._v("y")]),t._v(" direction, "),e("code",[t._v("step")]),t._v(": number of pixels to translate")]),e("h3",[t._v("translateXTo(x)")]),e("blockquote",[e("p",[t._v("v0.2.11+")])]),e("p",[t._v("Translate the "),e("code",[t._v("x")]),t._v(" direction to a specific position")]),e("h3",[t._v("translateYTo(y)")]),e("blockquote",[e("p",[t._v("v0.2.11+")])]),e("p",[t._v("Translate the "),e("code",[t._v("y")]),t._v(" direction to a specific position")]),e("h3",[t._v("reset()")]),e("p",[t._v("Revert to the default transformation")]),e("h3",[t._v("narrow(cx, cy)")]),e("ul",[e("li",[e("p",[e("code",[t._v("cx")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),e("li",[e("p",[e("code",[t._v("cy")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),e("p",[t._v("Zoom out")]),e("h3",[t._v("enlarge(cx, cy)")]),e("ul",[e("li",[e("p",[e("code",[t._v("cx")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),e("li",[e("p",[e("code",[t._v("cy")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),e("p",[t._v("Zoom in")]),e("h3",[t._v("getTransformData()")]),e("blockquote",[e("p",[t._v("v0.1.1+")])]),e("p",[t._v("Get the current transform data, can be used for display")]),e("h3",[t._v("setTransformData(data)")]),e("blockquote",[e("p",[t._v("v0.1.1+")])]),e("p",[t._v('Dynamically set transform data, transform data can be obtained through the getTransformData method"')]),e("h3",[t._v("setScale(scale, cx, cy)")]),e("blockquote",[e("p",[t._v("v0.2.17+")])]),e("ul",[e("li",[e("p",[e("code",[t._v("cx")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),e("li",[e("p",[e("code",[t._v("cy")]),t._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),e("p",[t._v("Setting Zoom")])])}],v={},c=v,i=o("2877"),s=Object(i["a"])(c,a,n,!1,null,null,null);e["default"]=s.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0abe0f"],{"16c7":function(e,t,o){"use strict";o.r(t);var a=function(){var e=this;e._self._c;return e._m(0)},n=[function(){var e=this,t=e._self._c;return t("div",[t("h1",[e._v("View instance")]),t("p",[e._v("The "),t("code",[e._v("view")]),e._v(" instance is responsible for view operations, and can be obtained through "),t("code",[e._v("mindMap.view")])]),t("h2",[e._v("Methods")]),t("h3",[e._v("fit()")]),t("blockquote",[t("p",[e._v("v0.6.0+")])]),t("p",[e._v("Zoom the mind map to fit the canvas.")]),t("p",[e._v("Note that this method cannot be called immediately after calling the 'setData' and 'setFullData' methods, and needs to listen to the 'node_tree_render_end' event calls 'fit'.")]),t("h3",[e._v("translateX(step)")]),t("p",[e._v("Translate in the "),t("code",[e._v("x")]),e._v(" direction, "),t("code",[e._v("step")]),e._v(": number of pixels to translate")]),t("h3",[e._v("translateY(step)")]),t("p",[e._v("Translate in the "),t("code",[e._v("y")]),e._v(" direction, "),t("code",[e._v("step")]),e._v(": number of pixels to translate")]),t("h3",[e._v("translateXTo(x)")]),t("blockquote",[t("p",[e._v("v0.2.11+")])]),t("p",[e._v("Translate the "),t("code",[e._v("x")]),e._v(" direction to a specific position")]),t("h3",[e._v("translateYTo(y)")]),t("blockquote",[t("p",[e._v("v0.2.11+")])]),t("p",[e._v("Translate the "),t("code",[e._v("y")]),e._v(" direction to a specific position")]),t("h3",[e._v("reset()")]),t("p",[e._v("Revert to the default transformation")]),t("h3",[e._v("narrow(cx, cy)")]),t("ul",[t("li",[t("p",[t("code",[e._v("cx")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),t("li",[t("p",[t("code",[e._v("cy")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),t("p",[e._v("Zoom out")]),t("h3",[e._v("enlarge(cx, cy)")]),t("ul",[t("li",[t("p",[t("code",[e._v("cx")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),t("li",[t("p",[t("code",[e._v("cy")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),t("p",[e._v("Zoom in")]),t("h3",[e._v("getTransformData()")]),t("blockquote",[t("p",[e._v("v0.1.1+")])]),t("p",[e._v("Get the current transform data, can be used for display")]),t("h3",[e._v("setTransformData(data)")]),t("blockquote",[t("p",[e._v("v0.1.1+")])]),t("p",[e._v('Dynamically set transform data, transform data can be obtained through the getTransformData method"')]),t("h3",[e._v("setScale(scale, cx, cy)")]),t("blockquote",[t("p",[e._v("v0.2.17+")])]),t("ul",[t("li",[t("p",[t("code",[e._v("cx")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])]),t("li",[t("p",[t("code",[e._v("cy")]),e._v(":v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas")])])]),t("p",[e._v("Setting Zoom")])])}],v={},i=v,c=o("2877"),s=Object(c["a"])(i,a,n,!1,null,null,null);t["default"]=s.exports}}]);

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0b361e"],{"27ad":function(s,a,t){"use strict";t.r(a);var e=function(){var s=this;s._self._c;return s._m(0)},n=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("Watermark plugin")]),a("blockquote",[a("p",[s._v("0.2.24+")])]),a("p",[a("code",[s._v("Watermark")]),s._v(" instance is responsible for displaying the watermark.")]),a("p",[s._v("Please refer to the "),a("a",{attrs:{href:"/mind-map/#/doc/zh/constructor"}},[s._v("Instantiation Options")]),s._v(" of the "),a("code",[s._v("MindMap")]),s._v(" class for configuration.")]),a("h2",[s._v("Register")]),a("pre",{staticClass:"hljs"},[a("code",[a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" Watermark "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/Watermark.js'")]),s._v("\n"),a("span",{staticClass:"hljs-comment"},[s._v("// import Watermark from 'simple-mind-map/src/Watermark.js' Use this path for versions below v0.6.0")]),s._v("\n\nMindMap.usePlugin(Watermark)\n")])]),a("p",[s._v("After registration and instantiation of "),a("code",[s._v("MindMap")]),s._v(", the instance can be obtained through "),a("code",[s._v("mindMap.watermark")]),s._v(".")]),a("h2",[s._v("Methods")]),a("h3",[s._v("draw()")]),a("p",[s._v("Redraw the watermark.")]),a("p",[s._v("Note: For imprecise rendering, some watermarks beyond the visible area will be drawn. If you have extreme performance requirements, it is recommended to develop the watermark function yourself.")]),a("h3",[s._v("updateWatermark(config)")]),a("p",[s._v("Update watermark config. Example:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.watermark.updateWatermark({\n "),a("span",{staticClass:"hljs-attr"},[s._v("text")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'Watermark text'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("lineSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("angle")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("50")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textStyle")]),s._v(": {\n "),a("span",{staticClass:"hljs-attr"},[s._v("color")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'#000'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("opacity")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("fontSize")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("20")]),s._v("\n }\n})\n")])]),a("h3",[s._v("hasWatermark()")]),a("blockquote",[a("p",[s._v("v0.3.2+")])]),a("p",[s._v("Gets whether the watermark exists.")])])}],r={},i=r,l=t("2877"),v=Object(l["a"])(i,e,n,!1,null,null,null);a["default"]=v.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0b361e"],{"27ad":function(s,a,t){"use strict";t.r(a);var e=function(){var s=this;s._self._c;return s._m(0)},r=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("Watermark plugin")]),a("blockquote",[a("p",[s._v("0.2.24+")])]),a("p",[a("code",[s._v("Watermark")]),s._v(" instance is responsible for displaying the watermark.")]),a("p",[s._v("Please refer to the "),a("a",{attrs:{href:"/mind-map/#/doc/zh/constructor"}},[s._v("Instantiation Options")]),s._v(" of the "),a("code",[s._v("MindMap")]),s._v(" class for configuration.")]),a("h2",[s._v("Register")]),a("pre",{staticClass:"hljs"},[a("code",[a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" Watermark "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/Watermark.js'")]),s._v("\n"),a("span",{staticClass:"hljs-comment"},[s._v("// import Watermark from 'simple-mind-map/src/Watermark.js' Use this path for versions below v0.6.0")]),s._v("\n\nMindMap.usePlugin(Watermark)\n")])]),a("p",[s._v("After registration and instantiation of "),a("code",[s._v("MindMap")]),s._v(", the instance can be obtained through "),a("code",[s._v("mindMap.watermark")]),s._v(".")]),a("h2",[s._v("Methods")]),a("h3",[s._v("draw()")]),a("p",[s._v("Redraw the watermark.")]),a("p",[s._v("Note: For imprecise rendering, some watermarks beyond the visible area will be drawn. If you have extreme performance requirements, it is recommended to develop the watermark function yourself.")]),a("h3",[s._v("updateWatermark(config)")]),a("p",[s._v("Update watermark config. Example:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.watermark.updateWatermark({\n "),a("span",{staticClass:"hljs-attr"},[s._v("text")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'Watermark text'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("lineSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("angle")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("50")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textStyle")]),s._v(": {\n "),a("span",{staticClass:"hljs-attr"},[s._v("color")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'#000'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("opacity")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("fontSize")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("20")]),s._v("\n }\n})\n")])]),a("h3",[s._v("hasWatermark()")]),a("blockquote",[a("p",[s._v("v0.3.2+")])]),a("p",[s._v("Gets whether the watermark exists.")]),a("h3",[s._v("clear()")]),a("blockquote",[a("p",[s._v("v0.9.2+")])]),a("p",[s._v("Clear watermark.")])])}],n={},i=n,l=t("2877"),v=Object(l["a"])(i,e,r,!1,null,null,null);a["default"]=v.exports}}]);

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0b9b64"],{"33b0":function(t,s,a){"use strict";a.r(s);var n=function(){var t=this;t._self._c;return t._m(0)},i=[function(){var t=this,s=t._self._c;return s("div",[s("h1",[t._v("结构")]),s("p",[s("code",[t._v("simple-mind-map")]),t._v("目前支持四种结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图、timeline时间轴、timeline2时间轴2、fishbone鱼骨图、verticalTimelinev0.6.6+竖向时间轴)。")]),s("p",[t._v("可以在实例化"),s("code",[t._v("simple-mind-map")]),t._v("时通过选项指定使用的结构:")]),s("pre",{staticClass:"hljs"},[s("code",[s("span",{staticClass:"hljs-keyword"},[t._v("new")]),t._v(" MindMap({\n "),s("span",{staticClass:"hljs-comment"},[t._v("// ...")]),t._v("\n "),s("span",{staticClass:"hljs-attr"},[t._v("layout")]),t._v(": "),s("span",{staticClass:"hljs-string"},[t._v("'logicalStructure'")]),t._v("\n})\n")])]),s("p",[t._v("也可以动态切换结构:")]),s("pre",{staticClass:"hljs"},[s("code",[t._v("mindMap.setLayout("),s("span",{staticClass:"hljs-string"},[t._v("'organizationStructure'")]),t._v(")\n")])]),s("p",[t._v("获取当前使用的结构可以使用"),s("code",[t._v("getLayout")]),t._v("方法:")]),s("pre",{staticClass:"hljs"},[s("code",[s("span",{staticClass:"hljs-keyword"},[t._v("const")]),t._v(" layout = mindMap.getLayout()\n")])]),s("h2",[t._v("完整示例")]),s("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVVtrFDEU/iuHiMxWtrNb8Gndlnp7EFqR+tgUSWfS3WgmGSaZXiwLUgrWS0Hpg6Ag6os++ChCW8Q/0+72Z3iymZkd2z745sIsk3P5vpOc72S2yc00DddzTjqka6JMpBYMt3k6R5VIUp1Z2IaMrzVBq0WdK8vjJpg+k1JvLPE1GMBaphMIECGoMhaFihdZ6l2UGDRLPp2gdTphKSVUAVAluQVnc5GzoHIpvb3VgtNfB6cv9oe/nw1/HI/e75693BntHJ7uvTv7/I2qSCtjgUVWrPP7OuYGsycVNZZXpqjyKHvPh/tfRscHw4+7ZVrUZ6rHF7aYzi3mNaZgdg62HXFRSoi7X2Bb6G4EOusxJZ4yK7R6aLM8snnGA4QfOIbqQBoXUdyG+EZ5EI2xC4DLDsQ6yhOubNjj9q7k7vXW1r24ERSZt7WyTCieBVNNnxUzyzoe3f0ocQZKaiZvtnzTOjMlw0+H/sj8UbvfoABzgVFfyDjjygUvTzDOwV3Kcp7p5Oj16OjrebK/CS8hXZn46nH/qYLytbCVeUIJu6S1dRp7oI1wKsDMQPI1GzQhiLB12KaVIlyORdOBQOqeiJicCMb5B1M3vLoBUJmjD29P33z3RXuVnxy9Ojn+WdehVo1AIfUjr3RkbLhlE9z/gjB2IjqoT0O4zmTOnQCLOE+PosWn2/IzjtONC8txMJnluALoxmIdIsmMmaWkKOIOTzQlY3cRIOKJt5IqhnRb6K0HlkhWa7nKXIh3Uttdza3VCuYjKaInGFKfSYyrj2235YNL5IqlfOu2apvApbFb0u9nvriMKAlb/gYqpjHkJgkjYyipWhLW9lse6YaIbb8DM+321XEcQFqJIOPIiAc+doz1454r58+lhJokslWjZW59ImoGpdSBdrGyOp0sLtL3uej1Mfx6u51ulsyX814rmROW9QTylqgpi2OheqWhKj0s2vSPFc+UFRRFV2sERImNe0CaxHfA3fnhY6MVfmLG8LRwYAeq4aYEvyB+osMWvoYZXq0i4a5Z06uZ3jA8QxBKimm75Kvicy+22mUVtQ3I4A+xm1Zg"}})])}],e={},l=e,o=a("2877"),r=Object(o["a"])(l,n,i,!1,null,null,null);s["default"]=r.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0b9b64"],{"33b0":function(t,s,a){"use strict";a.r(s);var n=function(){var t=this;t._self._c;return t._m(0)},i=[function(){var t=this,s=t._self._c;return s("div",[s("h1",[t._v("结构")]),s("p",[s("code",[t._v("simple-mind-map")]),t._v("目前支持结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图、timeline时间轴、timeline2时间轴2、fishbone鱼骨图、verticalTimelinev0.6.6+竖向时间轴)。")]),s("p",[t._v("可以在实例化"),s("code",[t._v("simple-mind-map")]),t._v("时通过选项指定使用的结构:")]),s("pre",{staticClass:"hljs"},[s("code",[s("span",{staticClass:"hljs-keyword"},[t._v("new")]),t._v(" MindMap({\n "),s("span",{staticClass:"hljs-comment"},[t._v("// ...")]),t._v("\n "),s("span",{staticClass:"hljs-attr"},[t._v("layout")]),t._v(": "),s("span",{staticClass:"hljs-string"},[t._v("'logicalStructure'")]),t._v("\n})\n")])]),s("p",[t._v("也可以动态切换结构:")]),s("pre",{staticClass:"hljs"},[s("code",[t._v("mindMap.setLayout("),s("span",{staticClass:"hljs-string"},[t._v("'organizationStructure'")]),t._v(")\n")])]),s("p",[t._v("获取当前使用的结构可以使用"),s("code",[t._v("getLayout")]),t._v("方法:")]),s("pre",{staticClass:"hljs"},[s("code",[s("span",{staticClass:"hljs-keyword"},[t._v("const")]),t._v(" layout = mindMap.getLayout()\n")])]),s("h2",[t._v("完整示例")]),s("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVVtrFDEU/iuHiMxWtrNb8Gndlnp7EFqR+tgUSWfS3WgmGSaZXiwLUgrWS0Hpg6Ag6os++ChCW8Q/0+72Z3iymZkd2z745sIsk3P5vpOc72S2yc00DddzTjqka6JMpBYMt3k6R5VIUp1Z2IaMrzVBq0WdK8vjJpg+k1JvLPE1GMBaphMIECGoMhaFihdZ6l2UGDRLPp2gdTphKSVUAVAluQVnc5GzoHIpvb3VgtNfB6cv9oe/nw1/HI/e75693BntHJ7uvTv7/I2qSCtjgUVWrPP7OuYGsycVNZZXpqjyKHvPh/tfRscHw4+7ZVrUZ6rHF7aYzi3mNaZgdg62HXFRSoi7X2Bb6G4EOusxJZ4yK7R6aLM8snnGA4QfOIbqQBoXUdyG+EZ5EI2xC4DLDsQ6yhOubNjj9q7k7vXW1r24ERSZt7WyTCieBVNNnxUzyzoe3f0ocQZKaiZvtnzTOjMlw0+H/sj8UbvfoABzgVFfyDjjygUvTzDOwV3Kcp7p5Oj16OjrebK/CS8hXZn46nH/qYLytbCVeUIJu6S1dRp7oI1wKsDMQPI1GzQhiLB12KaVIlyORdOBQOqeiJicCMb5B1M3vLoBUJmjD29P33z3RXuVnxy9Ojn+WdehVo1AIfUjr3RkbLhlE9z/gjB2IjqoT0O4zmTOnQCLOE+PosWn2/IzjtONC8txMJnluALoxmIdIsmMmaWkKOIOTzQlY3cRIOKJt5IqhnRb6K0HlkhWa7nKXIh3Uttdza3VCuYjKaInGFKfSYyrj2235YNL5IqlfOu2apvApbFb0u9nvriMKAlb/gYqpjHkJgkjYyipWhLW9lse6YaIbb8DM+321XEcQFqJIOPIiAc+doz1454r58+lhJokslWjZW59ImoGpdSBdrGyOp0sLtL3uej1Mfx6u51ulsyX814rmROW9QTylqgpi2OheqWhKj0s2vSPFc+UFRRFV2sERImNe0CaxHfA3fnhY6MVfmLG8LRwYAeq4aYEvyB+osMWvoYZXq0i4a5Z06uZ3jA8QxBKimm75Kvicy+22mUVtQ3I4A+xm1Zg"}})])}],e={},l=e,o=a("2877"),r=Object(o["a"])(l,n,i,!1,null,null,null);s["default"]=r.exports}}]);

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-2d0dddce"],{"82ca":function(v,_,e){"use strict";e.r(_);var c=function(){var v=this;v._self._c;return v._m(0)},o=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("View实例")]),_("p",[_("code",[v._v("view")]),v._v("实例负责视图操作,可通过"),_("code",[v._v("mindMap.view")]),v._v("获取到该实例")]),_("h2",[v._v("方法")]),_("h3",[v._v("fit()")]),_("blockquote",[_("p",[v._v("v0.6.0+")])]),_("p",[v._v("缩放思维导图至适应画布。")]),_("h3",[v._v("translateX(step)")]),_("p",[_("code",[v._v("x")]),v._v("方向进行平移,"),_("code",[v._v("step")]),v._v(":要平移的像素")]),_("h3",[v._v("translateY(step)")]),_("p",[_("code",[v._v("y")]),v._v("方向进行平移,"),_("code",[v._v("step")]),v._v(":要平移的像素")]),_("h3",[v._v("translateXTo(x)")]),_("blockquote",[_("p",[v._v("v0.2.11+")])]),_("p",[v._v("平移"),_("code",[v._v("x")]),v._v("方向到指定位置")]),_("h3",[v._v("translateYTo(y)")]),_("blockquote",[_("p",[v._v("v0.2.11+")])]),_("p",[v._v("平移"),_("code",[v._v("y")]),v._v("方向到指定位置")]),_("h3",[v._v("reset()")]),_("p",[v._v("恢复到默认的变换")]),_("h3",[v._v("narrow(cx, cy)")]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("缩小")]),_("h3",[v._v("enlarge(cx, cy)")]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("放大")]),_("h3",[v._v("getTransformData()")]),_("blockquote",[_("p",[v._v("v0.1.1+")])]),_("p",[v._v("获取当前变换数据,可用于回显")]),_("h3",[v._v("setTransformData(data)")]),_("blockquote",[_("p",[v._v("v0.1.1+")])]),_("p",[v._v("动态设置变换数据可以通过getTransformData方法获取变换数据")]),_("h3",[v._v("setScale(scale, cx, cy)")]),_("blockquote",[_("p",[v._v("v0.2.17+")])]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("设置缩放")])])}],t={},p=t,a=e("2877"),l=Object(a["a"])(p,c,o,!1,null,null,null);_["default"]=l.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0dddce"],{"82ca":function(v,_,e){"use strict";e.r(_);var c=function(){var v=this;v._self._c;return v._m(0)},t=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("View实例")]),_("p",[_("code",[v._v("view")]),v._v("实例负责视图操作,可通过"),_("code",[v._v("mindMap.view")]),v._v("获取到该实例")]),_("h2",[v._v("方法")]),_("h3",[v._v("fit()")]),_("blockquote",[_("p",[v._v("v0.6.0+")])]),_("p",[v._v("缩放思维导图至适应画布。")]),_("p",[v._v("注意该方法不能在"),_("code",[v._v("setData")]),v._v("、"),_("code",[v._v("setFullData")]),v._v("方法调用后立即调用,需要监听"),_("code",[v._v("node_tree_render_end")]),v._v("事件调用"),_("code",[v._v("fit")]),v._v("。")]),_("h3",[v._v("translateX(step)")]),_("p",[_("code",[v._v("x")]),v._v("方向进行平移,"),_("code",[v._v("step")]),v._v(":要平移的像素")]),_("h3",[v._v("translateY(step)")]),_("p",[_("code",[v._v("y")]),v._v("方向进行平移,"),_("code",[v._v("step")]),v._v(":要平移的像素")]),_("h3",[v._v("translateXTo(x)")]),_("blockquote",[_("p",[v._v("v0.2.11+")])]),_("p",[v._v("平移"),_("code",[v._v("x")]),v._v("方向到指定位置")]),_("h3",[v._v("translateYTo(y)")]),_("blockquote",[_("p",[v._v("v0.2.11+")])]),_("p",[v._v("平移"),_("code",[v._v("y")]),v._v("方向到指定位置")]),_("h3",[v._v("reset()")]),_("p",[v._v("恢复到默认的变换")]),_("h3",[v._v("narrow(cx, cy)")]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("缩小")]),_("h3",[v._v("enlarge(cx, cy)")]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("放大")]),_("h3",[v._v("getTransformData()")]),_("blockquote",[_("p",[v._v("v0.1.1+")])]),_("p",[v._v("获取当前变换数据,可用于回显")]),_("h3",[v._v("setTransformData(data)")]),_("blockquote",[_("p",[v._v("v0.1.1+")])]),_("p",[v._v("动态设置变换数据可以通过getTransformData方法获取变换数据")]),_("h3",[v._v("setScale(scale, cx, cy)")]),_("blockquote",[_("p",[v._v("v0.2.17+")])]),_("ul",[_("li",[_("p",[_("code",[v._v("cx")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])]),_("li",[_("p",[_("code",[v._v("cy")]),v._v("v0.6.4+)以画布指定位置进行缩放,默认为画布中心点")])])]),_("p",[v._v("设置缩放")])])}],o={},a=o,p=e("2877"),l=Object(p["a"])(a,c,t,!1,null,null,null);_["default"]=l.exports}}]);

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0de01b"],{"848a":function(s,a,t){"use strict";t.r(a);var n=function(){var s=this;s._self._c;return s._m(0)},v=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("Watermark插件")]),a("blockquote",[a("p",[s._v("0.2.24+")])]),a("p",[a("code",[s._v("Watermark")]),s._v("插件负责显示水印。")]),a("p",[s._v("配置请参考"),a("code",[s._v("MindMap")]),s._v("类的"),a("a",{attrs:{href:"/mind-map/#/doc/zh/constructor"}},[s._v("实例化选项")]),s._v("。")]),a("h2",[s._v("注册")]),a("pre",{staticClass:"hljs"},[a("code",[a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" Watermark "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/Watermark.js'")]),s._v("\n"),a("span",{staticClass:"hljs-comment"},[s._v("// import Watermark from 'simple-mind-map/src/Watermark.js' v0.6.0以下版本使用该路径")]),s._v("\n\nMindMap.usePlugin(Watermark)\n")])]),a("p",[s._v("注册完且实例化"),a("code",[s._v("MindMap")]),s._v("后可通过"),a("code",[s._v("mindMap.watermark")]),s._v("获取到该实例。")]),a("h2",[s._v("方法")]),a("h3",[s._v("draw()")]),a("p",[s._v("重新绘制水印。")]),a("p",[s._v("注意:非精确绘制,会绘制一些超出可视区域的水印,如果对性能有极致要求,推荐自行开发水印功能。")]),a("h3",[s._v("updateWatermark(config)")]),a("p",[s._v("更新水印配置。示例:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.watermark.updateWatermark({\n "),a("span",{staticClass:"hljs-attr"},[s._v("text")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'水印文字'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("lineSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("angle")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("50")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textStyle")]),s._v(": {\n "),a("span",{staticClass:"hljs-attr"},[s._v("color")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'#000'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("opacity")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("fontSize")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("20")]),s._v("\n }\n})\n")])]),a("h3",[s._v("hasWatermark()")]),a("blockquote",[a("p",[s._v("v0.3.2+")])]),a("p",[s._v("获取是否存在水印。")])])}],_={},r=_,l=t("2877"),i=Object(l["a"])(r,n,v,!1,null,null,null);a["default"]=i.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0de01b"],{"848a":function(s,a,t){"use strict";t.r(a);var n=function(){var s=this;s._self._c;return s._m(0)},v=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("Watermark插件")]),a("blockquote",[a("p",[s._v("0.2.24+")])]),a("p",[a("code",[s._v("Watermark")]),s._v("插件负责显示水印。")]),a("p",[s._v("配置请参考"),a("code",[s._v("MindMap")]),s._v("类的"),a("a",{attrs:{href:"/mind-map/#/doc/zh/constructor"}},[s._v("实例化选项")]),s._v("。")]),a("h2",[s._v("注册")]),a("pre",{staticClass:"hljs"},[a("code",[a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),a("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" Watermark "),a("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),a("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/Watermark.js'")]),s._v("\n"),a("span",{staticClass:"hljs-comment"},[s._v("// import Watermark from 'simple-mind-map/src/Watermark.js' v0.6.0以下版本使用该路径")]),s._v("\n\nMindMap.usePlugin(Watermark)\n")])]),a("p",[s._v("注册完且实例化"),a("code",[s._v("MindMap")]),s._v("后可通过"),a("code",[s._v("mindMap.watermark")]),s._v("获取到该实例。")]),a("h2",[s._v("方法")]),a("h3",[s._v("draw()")]),a("p",[s._v("重新绘制水印。")]),a("p",[s._v("注意:非精确绘制,会绘制一些超出可视区域的水印,如果对性能有极致要求,推荐自行开发水印功能。")]),a("h3",[s._v("updateWatermark(config)")]),a("p",[s._v("更新水印配置。示例:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.watermark.updateWatermark({\n "),a("span",{staticClass:"hljs-attr"},[s._v("text")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'水印文字'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("lineSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textSpacing")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("angle")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("50")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("textStyle")]),s._v(": {\n "),a("span",{staticClass:"hljs-attr"},[s._v("color")]),s._v(": "),a("span",{staticClass:"hljs-string"},[s._v("'#000'")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("opacity")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v(",\n "),a("span",{staticClass:"hljs-attr"},[s._v("fontSize")]),s._v(": "),a("span",{staticClass:"hljs-number"},[s._v("20")]),s._v("\n }\n})\n")])]),a("h3",[s._v("hasWatermark()")]),a("blockquote",[a("p",[s._v("v0.3.2+")])]),a("p",[s._v("获取是否存在水印。")]),a("h3",[s._v("clear()")]),a("blockquote",[a("p",[s._v("v0.9.2+")])]),a("p",[s._v("清除水印。")])])}],_={},r=_,l=t("2877"),p=Object(l["a"])(r,n,v,!1,null,null,null);a["default"]=p.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-2d0f0784.js vendored Normal file
View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0f0784"],{"9d03":function(e,t,n){"use strict";n.r(t);var i=function(){var e=this;e._self._c;return e._m(0)},d=[function(){var e=this,t=e._self._c;return t("div",[t("h1",[e._v("TextEdit instance")]),t("p",[e._v("Node text editing instance. It can be obtained through "),t("code",[e._v("mindMap.renderer.textEdit")]),e._v(".")]),t("h2",[e._v("Methods")]),t("h3",[e._v("isShowTextEdit()")]),t("p",[e._v("Get whether the current text editing box is in a display state, that is, whether it is in a text editing state.")]),t("h3",[e._v("hideEditTextBox()")]),t("p",[e._v("Hiding the text editing box will set the content of the current text editing box as node text.")]),t("h3",[e._v("registerTmpShortcut()")]),t("p",[e._v("Register temporary shortcut keys, which means editing can be completed through the Enter and Tab keys.")]),t("h3",[e._v("show({ node})")]),t("ul",[t("li",[t("code",[e._v("node")]),e._v("Node instance to enter for editing")])]),t("p",[e._v("Manually enable node editing. By default, it will enter node editing when double clicking or pressing F2 on the node.")])])}],o={},h=o,r=n("2877"),s=Object(r["a"])(h,i,d,!1,null,null,null);t["default"]=s.exports}}]);

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d20ff53"],{b69b:function(s,t,a){"use strict";a.r(t);var n=function(){var s=this;s._self._c;return s._m(0)},e=[function(){var s=this,t=s._self._c;return t("div",[t("h1",[s._v("修改鼠标滚轮的行为")]),t("p",[s._v("鼠标滚轮的行为支持放大缩小画布和上下移动画布,可以在实例化时通过配置指定:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelAction")]),s._v(": "),t("span",{staticClass:"hljs-string"},[s._v("'zoom'")]),t("span",{staticClass:"hljs-comment"},[s._v("// zoom放大缩小、move上下移动")]),s._v("\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 当mousewheelAction设为move时可以通过该属性控制鼠标滚动一下视图移动的步长单位px")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelMoveStep")]),s._v(": "),t("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n})\n")])]),t("p",[s._v("如果需要动态的切换行为可以使用"),t("code",[s._v("updateConfig")]),s._v("方法:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.updateConfig({\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelAction")]),s._v(": "),t("span",{staticClass:"hljs-string"},[s._v("'move'")]),s._v("\n})\n")])]),t("p",[s._v("此外也支持让你自行处理鼠标滚轮事件:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("customHandleMousewheel")]),s._v(": "),t("span",{staticClass:"hljs-function"},[s._v("("),t("span",{staticClass:"hljs-params"},[s._v("e")]),s._v(") =>")]),s._v(" {\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 你的自定义逻辑")]),s._v("\n }\n})\n")])]),t("p",[s._v("当传了"),t("code",[s._v("customHandleMousewheel")]),s._v("选项,"),t("code",[s._v("mousewheelAction")]),s._v("选项将不生效。")]),t("h2",[s._v("完整示例")]),t("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVU+P20QU/ypPRshZlNipxCkkpeXPAYlFqNedFXLsSTJlPGM842SXyBKqkFpKK4FAQiqXLZcWCXFCiO628GU2yfIteOPxON6QAzciOZp57/fe7828P7P0bmdZMC+oN/CGKs5ZpkFRXWQ3iWBpJnMNS8jppAtSHMpCaJp0Qc0izuXiDp1ACZNcpuCjB7+xOGQiOYwyqyKeQjGnvRSlvTTKiEcEABGcajAygxyBKDi38jCE1avvVl89Xv/1xfq3i82TL68e3tvce7F68MPV0+dExFIoDVGs2Zx+JBOq0HobUefo+IAIh4qLPKdC30awFIjDk3T8z6VM/QpkqB7cXz/+6e+XZ+uz++uLJ1evfr16+ujyj3PnQcvplFM8uqKLGaW8cdU5gNFNWJqYr7EE84gXFAF7paMRWH54G/xUzqkPg1piPNX3ERRZEmn6rhQTNu1UHKjbiWGwjwFPpUs8W2mO16Ss0wq2deV04VLlOCgfQCLjIkW3wZTq9zk1y3dOP0g6fm2JUemICZr7B11rhbFGA+vd/IhnBMRriaxY0xNtxMRbn72wSbXFYH5l7cwA4xnjCR7NgI+2Pnbc7WXZZbo8f7Q5f7ZLdp1wD+nxVtfG/U8RuGUtc3ZMMH1HSm264GOpmK2KI5/Tifa74MeYOkzTcQUvD96y/QWAZb/58dvVN7/YoGyfXZ5/fXnxe7sIpej4Al1/YnsNPXbMtgvm/0Om9LaooN2PTQc4nKXHosRvGNopg/MFN5riaMBKxx3AMGFziHmk1Ih4dRDv0VQSr1LXAJZstU0pImQYorYNdJ60lHwcGYhVEj0cF1pjE9+KOYs/rSD7mhwtlsvdEXKtge3wwGmxeXaxevi86uWt7OXP6+//9KEsh6EldNE1kbrVMGxdBG6VPuX2Tm7VI5V4QWjnaN2xAVVpECtFvCatQevOXFoWLNGzAdzo91+vcABZUyg5RUZMWqWoasx8r+3erXO1NYzGSvJCW0MAU24D6Nc7LbPt5t/0M8qmM4S/2e9nJ455P+8bjjmN8ilDXuc1i5KEiakTNKEHdar/Y8Q3XAR10M0eHWKZVjnwup7NgHm5grtKCnwoK/ekVmAGmgFAPHwHbdcHIS6DHMcvS6lJVm+cy4WiOTohXt3Ae95GYzvTOlODMOQnnwl1qgKpVC8WvTFld/HYQcTZaSFiFcQyDbHGqVZ7asPQ1IcpvfIftRG5qQ=="}})])}],l={},v=l,c=a("2877"),i=Object(c["a"])(v,n,e,!1,null,null,null);t["default"]=i.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d20ff53"],{b69b:function(s,t,a){"use strict";a.r(t);var e=function(){var s=this;s._self._c;return s._m(0)},n=[function(){var s=this,t=s._self._c;return t("div",[t("h1",[s._v("修改鼠标滚轮的行为")]),t("p",[s._v("鼠标滚轮的行为支持放大缩小画布和上下移动画布,可以在实例化时通过配置指定:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelAction")]),s._v(": "),t("span",{staticClass:"hljs-string"},[s._v("'move'")]),t("span",{staticClass:"hljs-comment"},[s._v("// zoom放大缩小、move上下移动")]),s._v("\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 当mousewheelAction设为move时可以通过该属性控制鼠标滚动一下视图移动的步长单位px")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelMoveStep")]),s._v(": "),t("span",{staticClass:"hljs-number"},[s._v("100")]),s._v(",\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 鼠标缩放是否以鼠标当前位置为中心点,否则以画布中心点")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mouseScaleCenterUseMousePosition")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v(",\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 当mousewheelAction设为zoom时或者按住Ctrl键时默认向前滚动是缩小向后滚动是放大如果该属性设为true那么会反过来")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelZoomActionReverse")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v(",\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 禁止鼠标滚轮缩放你仍旧可以使用api进行缩放")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("disableMouseWheelZoom")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("false")]),s._v(",\n})\n")])]),t("p",[s._v("如果需要动态的切换行为可以使用"),t("code",[s._v("updateConfig")]),s._v("方法:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.updateConfig({\n "),t("span",{staticClass:"hljs-attr"},[s._v("mousewheelAction")]),s._v(": "),t("span",{staticClass:"hljs-string"},[s._v("'zoom'")]),s._v("\n})\n")])]),t("p",[s._v("此外也支持让你自行处理鼠标滚轮事件:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("customHandleMousewheel")]),s._v(": "),t("span",{staticClass:"hljs-function"},[s._v("("),t("span",{staticClass:"hljs-params"},[s._v("e")]),s._v(") =>")]),s._v(" {\n "),t("span",{staticClass:"hljs-comment"},[s._v("// 你的自定义逻辑")]),s._v("\n }\n})\n")])]),t("p",[s._v("当传了"),t("code",[s._v("customHandleMousewheel")]),s._v("选项,"),t("code",[s._v("mousewheelAction")]),s._v("选项将不生效。")]),t("h2",[s._v("完整示例")]),t("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVU+P20QU/ypPRshZlNipxCkkpeXPAYlFqNedFXLsSTJlPGM842SXyBKqkFpKK4FAQiqXLZcWCXFCiO628GU2yfIteOPxON6QAzciOZp57/fe7828P7P0bmdZMC+oN/CGKs5ZpkFRXWQ3iWBpJnMNS8jppAtSHMpCaJp0Qc0izuXiDp1ACZNcpuCjB7+xOGQiOYwyqyKeQjGnvRSlvTTKiEcEABGcajAygxyBKDi38jCE1avvVl89Xv/1xfq3i82TL68e3tvce7F68MPV0+dExFIoDVGs2Zx+JBOq0HobUefo+IAIh4qLPKdC30awFIjDk3T8z6VM/QpkqB7cXz/+6e+XZ+uz++uLJ1evfr16+ujyj3PnQcvplFM8uqKLGaW8cdU5gNFNWJqYr7EE84gXFAF7paMRWH54G/xUzqkPg1piPNX3ERRZEmn6rhQTNu1UHKjbiWGwjwFPpUs8W2mO16Ss0wq2deV04VLlOCgfQCLjIkW3wZTq9zk1y3dOP0g6fm2JUemICZr7B11rhbFGA+vd/IhnBMRriaxY0xNtxMRbn72wSbXFYH5l7cwA4xnjCR7NgI+2Pnbc7WXZZbo8f7Q5f7ZLdp1wD+nxVtfG/U8RuGUtc3ZMMH1HSm264GOpmK2KI5/Tifa74MeYOkzTcQUvD96y/QWAZb/58dvVN7/YoGyfXZ5/fXnxe7sIpej4Al1/YnsNPXbMtgvm/0Om9LaooN2PTQc4nKXHosRvGNopg/MFN5riaMBKxx3AMGFziHmk1Ih4dRDv0VQSr1LXAJZstU0pImQYorYNdJ60lHwcGYhVEj0cF1pjE9+KOYs/rSD7mhwtlsvdEXKtge3wwGmxeXaxevi86uWt7OXP6+//9KEsh6EldNE1kbrVMGxdBG6VPuX2Tm7VI5V4QWjnaN2xAVVpECtFvCatQevOXFoWLNGzAdzo91+vcABZUyg5RUZMWqWoasx8r+3erXO1NYzGSvJCW0MAU24D6Nc7LbPt5t/0M8qmM4S/2e9nJ455P+8bjjmN8ilDXuc1i5KEiakTNKEHdar/Y8Q3XAR10M0eHWKZVjnwup7NgHm5grtKCnwoK/ekVmAGmgFAPHwHbdcHIS6DHMcvS6lJVm+cy4WiOTohXt3Ae95GYzvTOlODMOQnnwl1qgKpVC8WvTFld/HYQcTZaSFiFcQyDbHGqVZ7asPQ1IcpvfIftRG5qQ=="}})])}],l={},v=l,c=a("2877"),i=Object(c["a"])(v,e,n,!1,null,null,null);t["default"]=i.exports}}]);

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d216037"],{c13f:function(s,t,n){"use strict";n.r(t);var a=function(){var s=this;s._self._c;return s._m(0)},e=[function(){var s=this,t=s._self._c;return t("div",[t("h1",[s._v("开启节点自由拖拽")]),t("p",[s._v("节点支持自由拖拽,也就是可以把它拖动到你指定的位置,默认是不开启的,如果需要开启可以在实例化"),t("code",[s._v("simple-mind-map")]),s._v("时传入开启的选项:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("enableFreeDrag")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v("\n})\n")])]),t("p",[s._v("也可以动态切换是否开启:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.updateConfig({\n "),t("span",{staticClass:"hljs-attr"},[s._v("enableFreeDrag")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),t("span",{staticClass:"hljs-comment"},[s._v("// false")]),s._v("\n})\n")])]),t("p",[s._v("自由拖拽很容器将节点拖的乱七八糟,所以也可以通过命令回到默认的位置:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.execCommand("),t("span",{staticClass:"hljs-string"},[s._v("'RESET_LAYOUT'")]),s._v(")\n")])]),t("p",[s._v("也可以使用快捷键"),t("code",[s._v("Ctrl + L")]),s._v("来恢复。")]),t("h2",[s._v("完整示例")]),t("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVd1uG0UUfpVhEVoH2buuxJVxSksbJKSEolAuUDeqxrtje8rszLIzm8SyVgoF1EKIFASiFdxAVQFCQFWBEE2oeJmsnb4FZ3b2L44veldLa82c853znZnzM1PrchQ52wmxelZf+jGNFJJEJdFFj9MwErFCUxSTYRsJviESrkjQRnKMGRM7m2SIUjSMRYhs8GBXFhuUBxs4MirPkiBmpBOCtBPiyLM8jpDHGVFIyzRyFfGEMSN3XZQ9/Tr7/GD2397sr+P5d5+efnF7fvtJdvfe6Y+/eNwXXCqEfUW3yTsiIBKs64haN7ZWPF6iqLwWEf5WTMjVGI8ACEdpDTGTJAdpqrt3ZgcPZvcfZYc/Zf/uZYePTu/8Ov/m8Wz/29n+09KPEqMRIw0/rRW0ehFNdcRnOZxtzBICiJeWyTW+OLOTRAFW5IrgQzpq5Z4QIhwPap7eUt8QuEoh/LQ4wezjB9nDg2fH90//eJj980n2eK+MOiaQynU8EYk6G3IZAtkl/hURhpgHLXtz7b216zfXL39w7f3rdum/ynrrvLnOGtkps10dgfVQIPwkJFw5I6LWGNHLNydvA0dhCYdWmHIS2yttYwVXgXvGu/55lhZ4VkNkxIrsKi32rNkPT0xdmHrSv7RwpoH+mLIgJlyDb9Q+FtwtZVlkOjn6cn708yLZWcIlpFu1rol7QRGUy0JW2lFO1aYQSjfSu0JSRQUHS5uRobLbyPYhdZCmrQK+WJ95K2lVuvK66V6EoCTn33+VHf5m4jVdfHK0f3L8d7P2BG/ZHFhvmk4GspbetpH+X6dS1fWGmt1eNViJM/RQr/D1XTPDYHrBRhEYPNBjsEOoH9Bt5DMs5apnFUFcJaHwrFxdAGhQa6sqBUjfBW0TWHpSQrAB1hCj9FR/kCglOLrkM+p/mEOawwOQ0+niYHoD2dlnfz6793tz+NioB+JzM8lGadp3DUlBCjEtkjZ6HxjPz4gFD/X5ylXfbVwfbKWaMHOTl4ox71mOa2Z7MQIcIkPHl9KzqmJwGjddJnOHBmrcQxe63VdyHEJRVXkxAUZIda7Ii1Z/Ly9mpHRVG+KBFCxRxhAhXb891C12SkT15jz9mNDRGOCvdbvRbsm8nPfVkjnE8YgCb+k1wkFAObSEEVShO0WBPGfEF8oIiqCrPTiE4s5zYLUtkwH9mjq3pODweOfuvUIBGagmimfB22zGiOPC0olhntOQ6GR1BrHYkSQGJ55VtPiS91rbjpWKZM912e5HXE6kI6Ts+LwzIPQWHNvBjE4S7kvHF6ELnUGUXFIbmqY4TGql/wPpBfrv"}})])}],l={},r=l,i=n("2877"),p=Object(i["a"])(r,a,e,!1,null,null,null);t["default"]=p.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d216037"],{c13f:function(s,t,n){"use strict";n.r(t);var a=function(){var s=this;s._self._c;return s._m(0)},e=[function(){var s=this,t=s._self._c;return t("div",[t("h1",[s._v("开启节点自由拖拽")]),t("blockquote",[t("p",[s._v("节点自由拖拽的连线可能不会符合你的预期,这个问题基本上不会改,所以自由拖拽功能不建议使用。")])]),t("p",[s._v("节点支持自由拖拽,也就是可以把它拖动到你指定的位置,默认是不开启的,如果需要开启可以在实例化"),t("code",[s._v("simple-mind-map")]),s._v("时传入开启的选项:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("new")]),s._v(" MindMap({\n "),t("span",{staticClass:"hljs-comment"},[s._v("// ...")]),s._v("\n "),t("span",{staticClass:"hljs-attr"},[s._v("enableFreeDrag")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v("\n})\n")])]),t("p",[s._v("也可以动态切换是否开启:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.updateConfig({\n "),t("span",{staticClass:"hljs-attr"},[s._v("enableFreeDrag")]),s._v(": "),t("span",{staticClass:"hljs-literal"},[s._v("true")]),t("span",{staticClass:"hljs-comment"},[s._v("// false")]),s._v("\n})\n")])]),t("p",[s._v("自由拖拽很容器将节点拖的乱七八糟,所以也可以通过命令回到默认的位置:")]),t("pre",{staticClass:"hljs"},[t("code",[s._v("mindMap.execCommand("),t("span",{staticClass:"hljs-string"},[s._v("'RESET_LAYOUT'")]),s._v(")\n")])]),t("p",[s._v("也可以使用快捷键"),t("code",[s._v("Ctrl + L")]),s._v("来恢复。")]),t("h2",[s._v("完整示例")]),t("iframe",{staticStyle:{width:"100%",height:"455px",border:"none"},attrs:{src:"https://wanglin2.github.io/playground/#eNrFVd1uG0UUfpVhEVoH2buuxJVxSksbJKSEolAuUDeqxrtje8rszLIzm8SyVgoF1EKIFASiFdxAVQFCQFWBEE2oeJmsnb4FZ3b2L44veldLa82c853znZnzM1PrchQ52wmxelZf+jGNFJJEJdFFj9MwErFCUxSTYRsJviESrkjQRnKMGRM7m2SIUjSMRYhs8GBXFhuUBxs4MirPkiBmpBOCtBPiyLM8jpDHGVFIyzRyFfGEMSN3XZQ9/Tr7/GD2397sr+P5d5+efnF7fvtJdvfe6Y+/eNwXXCqEfUW3yTsiIBKs64haN7ZWPF6iqLwWEf5WTMjVGI8ACEdpDTGTJAdpqrt3ZgcPZvcfZYc/Zf/uZYePTu/8Ov/m8Wz/29n+09KPEqMRIw0/rRW0ehFNdcRnOZxtzBICiJeWyTW+OLOTRAFW5IrgQzpq5Z4QIhwPap7eUt8QuEoh/LQ4wezjB9nDg2fH90//eJj980n2eK+MOiaQynU8EYk6G3IZAtkl/hURhpgHLXtz7b216zfXL39w7f3rdum/ynrrvLnOGtkps10dgfVQIPwkJFw5I6LWGNHLNydvA0dhCYdWmHIS2yttYwVXgXvGu/55lhZ4VkNkxIrsKi32rNkPT0xdmHrSv7RwpoH+mLIgJlyDb9Q+FtwtZVlkOjn6cn708yLZWcIlpFu1rol7QRGUy0JW2lFO1aYQSjfSu0JSRQUHS5uRobLbyPYhdZCmrQK+WJ95K2lVuvK66V6EoCTn33+VHf5m4jVdfHK0f3L8d7P2BG/ZHFhvmk4GspbetpH+X6dS1fWGmt1eNViJM/RQr/D1XTPDYHrBRhEYPNBjsEOoH9Bt5DMs5apnFUFcJaHwrFxdAGhQa6sqBUjfBW0TWHpSQrAB1hCj9FR/kCglOLrkM+p/mEOawwOQ0+niYHoD2dlnfz6793tz+NioB+JzM8lGadp3DUlBCjEtkjZ6HxjPz4gFD/X5ylXfbVwfbKWaMHOTl4ox71mOa2Z7MQIcIkPHl9KzqmJwGjddJnOHBmrcQxe63VdyHEJRVXkxAUZIda7Ii1Z/Ly9mpHRVG+KBFCxRxhAhXb891C12SkT15jz9mNDRGOCvdbvRbsm8nPfVkjnE8YgCb+k1wkFAObSEEVShO0WBPGfEF8oIiqCrPTiE4s5zYLUtkwH9mjq3pODweOfuvUIBGagmimfB22zGiOPC0olhntOQ6GR1BrHYkSQGJ55VtPiS91rbjpWKZM912e5HXE6kI6Ts+LwzIPQWHNvBjE4S7kvHF6ELnUGUXFIbmqY4TGql/wPpBfrv"}})])}],l={},r=l,i=n("2877"),p=Object(i["a"])(r,a,e,!1,null,null,null);t["default"]=p.exports}}]);

File diff suppressed because one or more lines are too long

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

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d216f87"],{c576:function(e,t,n){"use strict";n.r(t);var _=function(){var e=this;e._self._c;return e._m(0)},v=[function(){var e=this,t=e._self._c;return t("div",[t("h1",[e._v("TextEdit 实例")]),t("p",[e._v("节点文本编辑实例。可以通过"),t("code",[e._v("mindMap.renderer.textEdit")]),e._v("获取到。")]),t("h2",[e._v("方法")]),t("h3",[e._v("isShowTextEdit()")]),t("p",[e._v("获取当前文本编辑框是否处于显示状态,也就是是否处在文本编辑状态。")]),t("h3",[e._v("hideEditTextBox()")]),t("p",[e._v("隐藏文本编辑框,会将当前文本编辑框中的内容设置为节点文本。")]),t("h3",[e._v("registerTmpShortcut()")]),t("p",[e._v("注册临时快捷键,也就是可以通过 Enter 键和 Tab 键完成编辑。")]),t("h3",[e._v("show({ node})")]),t("ul",[t("li",[t("code",[e._v("node")]),e._v(":要进入编辑的节点实例")])]),t("p",[e._v("手动开启节点编辑。默认会在节点双击、按 F2 时进入节点编辑。")])])}],i={},r=i,d=n("2877"),o=Object(d["a"])(r,_,v,!1,null,null,null);t["default"]=o.exports}}]);

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21d064"],{d013:function(s,a,t){"use strict";t.r(a);var n=function(){var s=this;s._self._c;return s._m(0)},_=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("如何实现搜索替换")]),a("blockquote",[a("p",[s._v("需要先注册 Search 插件")])]),a("p",[s._v("要实现搜索替换很简单,你只要先创建两个输入框,两个按钮,然后调用相关方法即可。")]),a("p",[s._v("第一个输入框用于搜索,可以绑定一个回车事件,然后调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.search("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".searchText, "),a("span",{staticClass:"hljs-function"},[s._v("() =>")]),s._v(" {\n "),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".$refs.searchInputRef.focus()\n})\n")])]),a("p",[a("code",[s._v("search")]),s._v("方法调用一次就会跳转到下一个匹配的节点,当搜索文本改变后再调用,默认会重新搜索从头开始。")]),a("p",[a("code",[s._v("search")]),s._v("方法第二个参数是一个回调函数,当本次搜索完成,即在跳转到节点后调用,一般需要在这个回调函数里重新让你的输入框聚焦,因为激活节点会拿走焦点,所以你需要把焦点拿回来。")]),a("p",[s._v("第二个输入框用于替换,替换支持单个替换和全部替换,需要注意的是要先在调用了"),a("code",[s._v("search")]),s._v("方法后才能调用这两个方法,单个替换只需要调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.replace("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".replaceText, "),a("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v(")\n")])]),a("p",[s._v("第二个参数传"),a("code",[s._v("true")]),s._v("会在替换完成后自动跳转到下一个匹配的节点,这样可以进行连续替换。")]),a("p",[s._v("要进行全部替换可以调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.replaceAll("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".replaceText)\n")])]),a("p",[s._v("最后你可以通过监听"),a("code",[s._v("search_info_change")]),s._v("方法来获取匹配的节点数量和当前定位到的索引:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.on("),a("span",{staticClass:"hljs-string"},[s._v("'search_info_change'")]),s._v(", "),a("span",{staticClass:"hljs-function"},[a("span",{staticClass:"hljs-params"},[s._v("data")]),s._v(" =>")]),s._v(" {\n "),a("span",{staticClass:"hljs-built_in"},[s._v("console")]),s._v(".log("),a("span",{staticClass:"hljs-string"},[s._v("'当前所在:'")]),s._v("+ (data.currentIndex + "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v("), "),a("span",{staticClass:"hljs-string"},[s._v("'匹配总数:'")]),s._v(" + data.total)\n})\n")])])])}],c={},l=c,e=t("2877"),i=Object(e["a"])(l,n,_,!1,null,null,null);a["default"]=i.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21d064"],{d013:function(s,a,t){"use strict";t.r(a);var n=function(){var s=this;s._self._c;return s._m(0)},_=[function(){var s=this,a=s._self._c;return a("div",[a("h1",[s._v("如何实现搜索替换")]),a("blockquote",[a("p",[s._v("需要先注册 Search 插件")])]),a("p",[s._v("要实现搜索替换很简单,你只要先创建两个输入框,两个按钮,然后调用相关方法即可。")]),a("p",[s._v("第一个输入框用于搜索,可以绑定一个回车事件,然后调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.search("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".searchText, "),a("span",{staticClass:"hljs-function"},[s._v("() =>")]),s._v(" {\n "),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".$refs.searchInputRef.focus()\n})\n")])]),a("p",[a("code",[s._v("search")]),s._v("方法调用一次就会跳转到下一个匹配的节点,当搜索文本改变后再调用,默认会重新搜索从头开始。")]),a("p",[a("code",[s._v("search")]),s._v("方法第二个参数是一个回调函数,当本次搜索完成,即在跳转到节点后调用,一般需要在这个回调函数里重新让你的输入框聚焦,因为激活节点会拿走焦点,所以你需要把焦点拿回来。")]),a("p",[s._v("第二个输入框用于替换,替换支持单个替换和全部替换,需要注意的是要先在调用了"),a("code",[s._v("search")]),s._v("方法后才能调用这两个方法,单个替换只需要调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.replace("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".replaceText, "),a("span",{staticClass:"hljs-literal"},[s._v("true")]),s._v(")\n")])]),a("p",[s._v("第二个参数传"),a("code",[s._v("true")]),s._v("会在替换完成后自动跳转到下一个匹配的节点,这样可以进行连续替换。")]),a("p",[s._v("要进行全部替换可以调用如下方法:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.search.replaceAll("),a("span",{staticClass:"hljs-built_in"},[s._v("this")]),s._v(".replaceText)\n")])]),a("p",[s._v("最后你可以通过监听"),a("code",[s._v("search_info_change")]),s._v("方法来获取匹配的节点数量和当前定位到的索引:")]),a("pre",{staticClass:"hljs"},[a("code",[s._v("mindMap.on("),a("span",{staticClass:"hljs-string"},[s._v("'search_info_change'")]),s._v(", "),a("span",{staticClass:"hljs-function"},[a("span",{staticClass:"hljs-params"},[s._v("data")]),s._v(" =>")]),s._v(" {\n "),a("span",{staticClass:"hljs-built_in"},[s._v("console")]),s._v(".log("),a("span",{staticClass:"hljs-string"},[s._v("'当前所在:'")]),s._v("+ (data.currentIndex + "),a("span",{staticClass:"hljs-number"},[s._v("1")]),s._v("), "),a("span",{staticClass:"hljs-string"},[s._v("'匹配总数:'")]),s._v(" + data.total)\n})\n")])]),a("p",[s._v("如果是只读模式下搜索,搜索匹配到的节点不会被激活,而是被高亮。")])])}],c={},l=c,e=t("2877"),i=Object(e["a"])(l,n,_,!1,null,null,null);a["default"]=i.exports}}]);

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d221c76"],{cc99:function(s,t,i){"use strict";i.r(t);var n=function(){var s=this;s._self._c;return s._m(0)},a=[function(){var s=this,t=s._self._c;return t("div",[t("h1",[s._v("开启节点富文本编辑")]),t("p",[s._v("默认节点编辑是不支持富文本模式的,如果要开启需要使用富文本编辑插件,但是富文本编辑模式目前存在缺陷,详情可以阅读"),t("a",{attrs:{href:"https://wanglin2.github.io/mind-map/#/doc/zh/richText"}},[s._v("richText")]),s._v("。")]),t("p",[s._v("富文本编辑的优势就是可以对一个节点内的部分文本设置样式所以通常来说还需要搭配一个悬浮的工具栏这个功能默认也是没有的涉及到UI的功能一般都不提供,所以也需要你自行开发,如何渲染这个悬浮工具栏可以阅读"),t("a",{attrs:{href:"https://wanglin2.github.io/mind-map/#/doc/zh/course16"}},[s._v("如何渲染富文本的悬浮工具栏")]),s._v("。")]),t("p",[s._v("如果也你需要动态切换是否开启富文本编辑的功能可以参考如下代码:")]),t("pre",{staticClass:"hljs"},[t("code",[t("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),t("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),t("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),t("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" RichText "),t("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),t("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/RichText.js'")]),s._v("\n"),t("span",{staticClass:"hljs-comment"},[s._v("// import RichText from 'simple-mind-map/src/RichText.js' v0.6.0以下版本使用该路径")]),s._v("\n\n"),t("span",{staticClass:"hljs-comment"},[s._v("// 动态开启富文本编辑")]),s._v("\nmindMap.addPlugin(RichText)\n\n"),t("span",{staticClass:"hljs-comment"},[s._v("// 动态关闭富文本编辑")]),s._v("\nmindMap.removePlugin(RichText)\n")])]),t("p",[s._v("如果你使用的是"),t("code",[s._v("simpleMindMap.umd.js")]),s._v("或"),t("code",[s._v("simpleMindMap.esm.js")]),s._v("这种打包后的完整版,那么是不支持切换的,默认是就是开启的,如有相关需求可以提"),t("a",{attrs:{href:"https://github.com/wanglin2/mind-map/issues"}},[s._v("issue")]),s._v("。")])])}],c={},e=c,p=i("2877"),l=Object(p["a"])(e,n,a,!1,null,null,null);t["default"]=l.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d221c76"],{cc99:function(s,n,t){"use strict";t.r(n);var i=function(){var s=this;s._self._c;return s._m(0)},a=[function(){var s=this,n=s._self._c;return n("div",[n("h1",[s._v("开启节点富文本编辑")]),n("p",[s._v("默认节点编辑是不支持富文本模式的,如果要开启需要使用富文本编辑插件。")]),n("p",[s._v("富文本编辑的优势就是可以对一个节点内的部分文本设置样式所以通常来说还需要搭配一个悬浮的工具栏这个功能默认也是没有的涉及到UI的功能都不提供,所以也需要你自行开发,如何渲染这个悬浮工具栏可以阅读"),n("a",{attrs:{href:"https://wanglin2.github.io/mind-map/#/doc/zh/course16"}},[s._v("如何渲染富文本的悬浮工具栏")]),s._v("。")]),n("p",[s._v("如果也你需要动态切换是否开启富文本编辑的功能可以参考如下代码:")]),n("pre",{staticClass:"hljs"},[n("code",[n("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" MindMap "),n("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),n("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map'")]),s._v("\n"),n("span",{staticClass:"hljs-keyword"},[s._v("import")]),s._v(" RichText "),n("span",{staticClass:"hljs-keyword"},[s._v("from")]),s._v(" "),n("span",{staticClass:"hljs-string"},[s._v("'simple-mind-map/src/plugins/RichText.js'")]),s._v("\n"),n("span",{staticClass:"hljs-comment"},[s._v("// import RichText from 'simple-mind-map/src/RichText.js' v0.6.0以下版本使用该路径")]),s._v("\n\n"),n("span",{staticClass:"hljs-comment"},[s._v("// 动态开启富文本编辑")]),s._v("\nmindMap.addPlugin(RichText)\n\n"),n("span",{staticClass:"hljs-comment"},[s._v("// 动态关闭富文本编辑")]),s._v("\nmindMap.removePlugin(RichText)\n")])]),n("p",[s._v("如果你使用的是"),n("code",[s._v("simpleMindMap.umd.js")]),s._v("或"),n("code",[s._v("simpleMindMap.esm.js")]),s._v("这种打包后的完整版,那么是不支持切换的,默认是就是开启的。")])])}],c={},p=c,l=t("2877"),e=Object(l["a"])(p,i,a,!1,null,null,null);n["default"]=e.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-3b7380d1.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

View File

@@ -1,7 +1,7 @@
<!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?8fccd498baeca61b68aa" rel="stylesheet"><link href="dist/css/app.css?8fccd498baeca61b68aa" 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><link href="dist/css/chunk-vendors.css?dc223b3a0a24b7dd7194" rel="stylesheet"><link href="dist/css/app.css?dc223b3a0a24b7dd7194" 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({
@@ -66,4 +66,4 @@
// 可以通过window.$bus.$on()来监听应用的一些事件
// 实例化页面
window.initApp()
}</script><script src="dist/js/chunk-vendors.js?8fccd498baeca61b68aa"></script><script src="dist/js/app.js?8fccd498baeca61b68aa"></script></body></html>
}</script><script src="dist/js/chunk-vendors.js?dc223b3a0a24b7dd7194"></script><script src="dist/js/app.js?dc223b3a0a24b7dd7194"></script></body></html>

View File

@@ -162,19 +162,16 @@ class MindMap {
render(callback, source = '') {
this.batchExecution.push('render', () => {
this.initTheme()
this.renderer.reRender = false
this.renderer.render(callback, source)
})
}
// 重新渲染
reRender(callback, source = '') {
this.batchExecution.push('render', () => {
this.clearDraw()
this.initTheme()
this.renderer.reRender = true
this.renderer.render(callback, source)
})
this.renderer.reRender = true // 标记为重新渲染
this.renderer.clearCache() // 清空节点缓存池
this.clearDraw() // 清空画布
this.render(callback, (source = ''))
}
// 获取或更新容器尺寸位置信息
@@ -410,20 +407,34 @@ class MindMap {
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
// 克隆一份数据
let clone = svg.clone()
// 如果实际图形宽高超出了屏幕宽高,且存在水印的话需要重新绘制水印,否则会出现超出部分没有水印的问题
if (
!ignoreWatermark &&
(rect.width > origWidth || rect.height > origHeight) &&
this.watermark &&
this.watermark.hasWatermark()
) {
this.width = rect.width
this.height = rect.height
this.watermark.draw()
clone = svg.clone()
this.width = origWidth
this.height = origHeight
this.watermark.draw()
// 是否存在水印
const hasWatermark = this.watermark && this.watermark.hasWatermark()
if (!ignoreWatermark && hasWatermark) {
this.watermark.isInExport = true
// 是否是仅导出时需要水印
const { onlyExport } = this.opt.watermarkConfig
// 是否需要重新绘制水印
const needReDrawWatermark =
rect.width > origWidth || rect.height > origHeight
// 如果实际图形宽高超出了屏幕宽高,且存在水印的话需要重新绘制水印,否则会出现超出部分没有水印的问题
if (needReDrawWatermark) {
this.width = rect.width
this.height = rect.height
this.watermark.onResize()
clone = svg.clone()
this.width = origWidth
this.height = origHeight
this.watermark.onResize()
} else if (onlyExport) {
// 如果是仅导出时需要水印,那么需要进行绘制
this.watermark.onResize()
clone = svg.clone()
}
// 如果是仅导出时需要水印,需要清除
if (onlyExport) {
this.watermark.clear()
}
this.watermark.isInExport = false
}
// 添加必要的样式
clone.add(SVG(`<style>${cssContent}</style>`))
@@ -495,7 +506,10 @@ class MindMap {
}
// 移除插件
;[...MindMap.pluginList].forEach(plugin => {
if (this[plugin.instanceName] && this[plugin.instanceName].beforePluginDestroy) {
if (
this[plugin.instanceName] &&
this[plugin.instanceName].beforePluginDestroy
) {
this[plugin.instanceName].beforePluginDestroy()
}
this[plugin.instanceName] = null

View File

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

View File

@@ -332,12 +332,6 @@ export const ERROR_TYPES = {
EXPORT_LOAD_IMAGE_ERROR: 'export_load_image_error'
}
// a4纸的宽高
export const a4Size = {
width: 592.28,
height: 841.89
}
// css
export const cssContent = `
/* 鼠标hover和激活时渲染的矩形 */

View File

@@ -40,6 +40,7 @@ export const defaultOpt = {
enableFreeDrag: false,
// 水印配置
watermarkConfig: {
onlyExport: false,// 是否仅在导出时添加水印
text: '',
lineSpacing: 100,
textSpacing: 100,
@@ -97,7 +98,7 @@ export const defaultOpt = {
// 是否在点击了画布外的区域时结束节点文本的编辑状态
isEndNodeTextEditOnClickOuter: true,
// 最大历史记录数
maxHistoryCount: 1000,
maxHistoryCount: 500,
// 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示
alwaysShowExpandBtn: false,
// 扩展节点可插入的图标
@@ -238,5 +239,22 @@ export const defaultOpt = {
*/
createNewNodeBehavior: CONSTANTS.CREATE_NEW_NODE_BEHAVIOR.DEFAULT,
// 当节点图片加载失败时显示的默认图片
defaultNodeImage: ''
defaultNodeImage: '',
// 是否将思维导图限制在画布内
// 比如向右拖动时,思维导图图形的最左侧到达画布中心时将无法继续向右拖动,其他同理
isLimitMindMapInCanvas: false,
// 当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas不再起作用
isLimitMindMapInCanvasWhenHasScrollbar: true,
// 在节点上粘贴剪贴板中的图片的处理方法默认是转换为data:url数据插入到节点中你可以通过该方法来将图片数据上传到服务器实现保存图片的url
// 可以传递一个异步方法接收Blob类型的图片数据需要返回如下结构
/*
{
url, // 图片url
size: {
width, // 图片的宽度
height //图片的高度
}
}
*/
handleNodePasteImg: null
}

View File

@@ -44,13 +44,10 @@ export default class KeyCommand {
this.isInSvg = true
})
this.mindMap.on('svg_mouseleave', () => {
if (this.mindMap.richText && this.mindMap.richText.showTextEdit) {
return
}
if (this.mindMap.renderer.textEdit.isShowTextEdit()) return
if (
this.mindMap.renderer.textEdit.showTextEdit ||
(this.mindMap.associativeLine &&
this.mindMap.associativeLine.showTextEdit)
this.mindMap.associativeLine &&
this.mindMap.associativeLine.showTextEdit
) {
return
}

View File

@@ -29,11 +29,13 @@ class Event extends EventEmitter {
// 绑定函数上下文
bindFn() {
this.onBodyMousedown = this.onBodyMousedown.bind(this)
this.onBodyClick = this.onBodyClick.bind(this)
this.onDrawClick = this.onDrawClick.bind(this)
this.onMousedown = this.onMousedown.bind(this)
this.onMousemove = this.onMousemove.bind(this)
this.onMouseup = this.onMouseup.bind(this)
this.onNodeMouseup = this.onNodeMouseup.bind(this)
this.onMousewheel = this.onMousewheel.bind(this)
this.onContextmenu = this.onContextmenu.bind(this)
this.onSvgMousedown = this.onSvgMousedown.bind(this)
@@ -44,12 +46,14 @@ class Event extends EventEmitter {
// 绑定事件
bind() {
document.body.addEventListener('mousedown', this.onBodyMousedown)
document.body.addEventListener('click', this.onBodyClick)
this.mindMap.svg.on('click', this.onDrawClick)
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
this.mindMap.svg.on('mousedown', this.onSvgMousedown)
window.addEventListener('mousemove', this.onMousemove)
window.addEventListener('mouseup', this.onMouseup)
this.on('node_mouseup', this.onNodeMouseup)
this.mindMap.el.addEventListener('wheel', this.onMousewheel)
this.mindMap.svg.on('contextmenu', this.onContextmenu)
this.mindMap.svg.on('mouseenter', this.onMouseenter)
@@ -59,11 +63,13 @@ class Event extends EventEmitter {
// 解绑事件
unbind() {
document.body.removeEventListener('mousedown', this.onBodyMousedown)
document.body.removeEventListener('click', this.onBodyClick)
this.mindMap.svg.off('click', this.onDrawClick)
this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
window.removeEventListener('mousemove', this.onMousemove)
window.removeEventListener('mouseup', this.onMouseup)
this.off('node_mouseup', this.onNodeMouseup)
this.mindMap.el.removeEventListener('wheel', this.onMousewheel)
this.mindMap.svg.off('contextmenu', this.onContextmenu)
this.mindMap.svg.off('mouseenter', this.onMouseenter)
@@ -76,6 +82,11 @@ class Event extends EventEmitter {
this.emit('draw_click', e)
}
// 页面的鼠标按下事件
onBodyMousedown(e) {
this.emit('body_mousedown', e)
}
// 页面的单击事件
onBodyClick(e) {
this.emit('body_click', e)
@@ -122,28 +133,33 @@ class Event extends EventEmitter {
// 鼠标松开事件
onMouseup(e) {
this.isLeftMousedown = false
this.isRightMousedown = false
this.isMiddleMousedown = false
this.onNodeMouseup()
this.emit('mouseup', e, this)
}
// 鼠标滚动
// 节点鼠标松开事件
onNodeMouseup() {
this.isLeftMousedown = false
this.isRightMousedown = false
this.isMiddleMousedown = false
}
// 鼠标滚动/触控板滑动
onMousewheel(e) {
e.stopPropagation()
e.preventDefault()
let dir
if (e.deltaY < 0) dir = CONSTANTS.DIR.UP
if (e.deltaY > 0) dir = CONSTANTS.DIR.DOWN
if (e.deltaX < 0) dir = CONSTANTS.DIR.LEFT
if (e.deltaX > 0) dir = CONSTANTS.DIR.RIGHT
const dirs = []
if (e.deltaY < 0) dirs.push(CONSTANTS.DIR.UP)
if (e.deltaY > 0) dirs.push(CONSTANTS.DIR.DOWN)
if (e.deltaX < 0) dirs.push(CONSTANTS.DIR.LEFT)
if (e.deltaX > 0) dirs.push(CONSTANTS.DIR.RIGHT)
// 判断是否是触控板
let isTouchPad = false
// mac、windows
if (e.wheelDeltaY === e.deltaY * -3 || Math.abs(e.wheelDeltaY) <= 10) {
isTouchPad = true
}
this.emit('mousewheel', e, dir, this, isTouchPad)
this.emit('mousewheel', e, dirs, this, isTouchPad)
}
// 鼠标右键菜单事件

View File

@@ -276,9 +276,6 @@ class Render {
})
// 插入同级节点
this.mindMap.keyCommand.addShortcut('Enter', () => {
if (this.textEdit.showTextEdit) {
return
}
this.mindMap.execCommand('INSERT_NODE')
})
// 插入父节点
@@ -323,16 +320,18 @@ class Render {
this.mindMap.keyCommand.addShortcut('Control+Down', () => {
this.mindMap.execCommand('DOWN_NODE')
})
// 复制节点、剪切节点、粘贴节点的快捷键需开发者自行注册实现可参考demo
// 复制节点、
this.mindMap.keyCommand.addShortcut('Control+c', () => {
this.copy()
})
this.mindMap.keyCommand.addShortcut('Control+v', () => {
this.onPaste()
})
// 剪切节点
this.mindMap.keyCommand.addShortcut('Control+x', () => {
this.cut()
})
// 粘贴节点
this.mindMap.keyCommand.addShortcut('Control+v', () => {
this.paste()
})
// 根节点居中显示
this.mindMap.keyCommand.addShortcut('Control+Enter', () => {
this.setRootNodeCenter()
@@ -387,6 +386,13 @@ class Render {
this.mindMap.keyCommand.restore()
}
// 清空节点缓存池
clearCache() {
this.layout.lru.clear()
this.nodeCache = {}
this.lastNodeCache = {}
}
// 渲染
render(callback = () => {}, source) {
// 如果当前还没有渲染完毕,不再触发渲染
@@ -431,6 +437,9 @@ class Render {
this.waitRenderingParams = []
this.render(...params)
} else {
if (this.reRender) {
this.reRender = false
}
// 触发一次保存,因为修改了渲染树的数据
if (
this.mindMap.richText &&
@@ -866,6 +875,7 @@ class Render {
// 复制节点
copy() {
this.beingCopyData = this.copyNode()
if (!this.beingCopyData) return
setDataToClipboard({
simpleMindMap: true,
data: this.beingCopyData
@@ -883,17 +893,13 @@ class Render {
})
}
// 粘贴节点
paste() {
if (this.beingCopyData) {
this.mindMap.execCommand('PASTE_NODE', this.beingCopyData)
}
}
// 粘贴事件
async onPaste() {
const { errorHandler, handleIsSplitByWrapOnPasteCreateNewNode } =
this.mindMap.opt
// 粘贴
async paste() {
const {
errorHandler,
handleIsSplitByWrapOnPasteCreateNewNode,
handleNodePasteImg
} = this.mindMap.opt
// 读取剪贴板的文字和图片
let text = null
let img = null
@@ -996,7 +1002,13 @@ class Render {
// 存在图片,则添加到当前激活节点
if (img) {
try {
let imgData = await loadImage(img)
let imgData = null
// 自定义图片处理函数
if (handleNodePasteImg && typeof handleNodePasteImg === 'function') {
imgData = await handleNodePasteImg(img)
} else {
imgData = await loadImage(img)
}
if (this.activeNodeList.length > 0) {
this.activeNodeList.forEach(node => {
this.mindMap.execCommand('SET_NODE_IMAGE', node, {
@@ -1013,7 +1025,9 @@ class Render {
}
} else {
// 粘贴节点数据
this.paste()
if (this.beingCopyData) {
this.mindMap.execCommand('PASTE_NODE', this.beingCopyData)
}
}
}
@@ -1205,7 +1219,7 @@ class Render {
// 复制节点
copyNode() {
if (this.activeNodeList.length <= 0) {
return
return null
}
const nodeList = getTopAncestorsFomNodeList(this.activeNodeList)
return nodeList.map(node => {
@@ -1363,7 +1377,7 @@ class Render {
0
)
this.mindMap.render(() => {
this.mindMap.view.reset()
this.setRootNodeCenter()
})
}

View File

@@ -21,6 +21,7 @@ export default class TextEdit {
this.showTextEdit = false
// 如果编辑过程中缩放画布了,那么缓存当前编辑的内容
this.cacheEditingText = ''
this.hasBodyMousedown = false
this.bindEvent()
}
@@ -38,7 +39,12 @@ export default class TextEdit {
// 隐藏文本编辑框
this.hideEditTextBox()
})
this.mindMap.on('body_mousedown', () => {
this.hasBodyMousedown = true
})
this.mindMap.on('body_click', () => {
if (!this.hasBodyMousedown) return
this.hasBodyMousedown = false
// 隐藏文本编辑框
if (this.mindMap.opt.isEndNodeTextEditOnClickOuter) {
this.hideEditTextBox()
@@ -126,6 +132,14 @@ export default class TextEdit {
})
}
// 获取当前文本编辑框是否处于显示状态,也就是是否处在文本编辑状态
isShowTextEdit() {
if (this.mindMap.richText) {
return this.mindMap.richText.showTextEdit
}
return this.showTextEdit
}
// 显示文本编辑框
// isInserting是否是刚创建的节点
// isFromKeyDown是否是在按键事件进入的编辑

View File

@@ -165,6 +165,11 @@ class Node {
this.top = 0
}
// 节点被删除时需要复位的数据
resetWhenDelete() {
this._isMouseenter = false
}
// 处理数据
handleData(data) {
data.data.expand = data.data.expand === false ? false : true
@@ -182,7 +187,10 @@ class Node {
}
// 如果没有返回内容,那么还是使用内置的节点内容
if (this._customNodeContent) {
this._customNodeContent.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
this._customNodeContent.setAttribute(
'xmlns',
'http://www.w3.org/1999/xhtml'
)
return
}
this._imgData = this.createImgNode()
@@ -694,6 +702,7 @@ class Node {
// 销毁节点,不但会从画布删除,而且原节点直接置空,后续无法再插回画布
destroy() {
if (!this.group) return
this.resetWhenDelete()
this.group.remove()
this.removeGeneralization()
this.removeLine()
@@ -825,9 +834,9 @@ class Node {
this.renderer.layout.renderLine(
this,
this._lines,
(line, node) => {
(...args) => {
// 添加样式
this.styleLine(line, node)
this.styleLine(...args)
},
this.style.getStyle('lineStyle', true)
)
@@ -882,19 +891,26 @@ class Node {
}
// 设置连线样式
styleLine(line, node) {
let width =
node.getSelfInhertStyle('lineWidth') || node.getStyle('lineWidth', true)
let color =
node.getSelfInhertStyle('lineColor') || node.getStyle('lineColor', true)
let dasharray =
node.getSelfInhertStyle('lineDasharray') ||
node.getStyle('lineDasharray', true)
this.style.line(line, {
width,
color,
dasharray
})
styleLine(line, childNode, enableMarker) {
const width =
childNode.getSelfInhertStyle('lineWidth') ||
childNode.getStyle('lineWidth', true)
const color =
childNode.getSelfInhertStyle('lineColor') ||
childNode.getStyle('lineColor', true)
const dasharray =
childNode.getSelfInhertStyle('lineDasharray') ||
childNode.getStyle('lineDasharray', true)
this.style.line(
line,
{
width,
color,
dasharray
},
enableMarker,
childNode
)
}
// 移除连线

View File

@@ -55,6 +55,9 @@ class Style {
// 构造函数
constructor(ctx) {
this.ctx = ctx
// 箭头图标
this._markerPath = null
this._marker = null
}
// 合并样式
@@ -190,8 +193,38 @@ class Style {
}
// 连线
line(node, { width, color, dasharray } = {}) {
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
line(line, { width, color, dasharray } = {}, enableMarker, childNode) {
line.stroke({ color, dasharray, width }).fill({ color: 'none' })
// 可以显示箭头
if (enableMarker) {
const showMarker = this.merge('showLineMarker', true)
const childNodeStyle = childNode.style
// 显示箭头
if (showMarker) {
// 创建子节点箭头标记
childNodeStyle._marker =
childNodeStyle._marker || childNodeStyle.createMarker()
// 设置样式
childNodeStyle._markerPath.stroke({ color }).fill({ color })
line.marker('end', childNodeStyle._marker)
} else if (childNodeStyle._marker) {
// 不显示箭头,则删除该子节点的箭头标记
line.attr('marker-end', '')
childNodeStyle._marker.remove()
childNodeStyle._marker = null
}
}
}
// 创建箭头
createMarker() {
return this.ctx.lineDraw.marker(20, 20, add => {
add.ref(8, 5)
add.size(20, 20)
add.attr('markerUnits', 'userSpaceOnUse')
add.attr('orient', 'auto-start-reverse')
this._markerPath = add.path('M0,0 L2,5 L0,10 L10,5 Z')
})
}
// 概要连线

View File

@@ -37,7 +37,7 @@ class View {
this.mindMap.event.on('drag', (e, event) => {
// 按住ctrl键拖动为多选
// 禁用拖拽
if (e.ctrlKey || this.mindMap.opt.isDisableDrag) {
if (e.ctrlKey || this.mindMap.opt.isDisableDrag) {
return
}
if (this.firstDrag) {
@@ -55,8 +55,8 @@ class View {
this.firstDrag = true
})
// 放大缩小视图
this.mindMap.event.on('mousewheel', (e, dir, event, isTouchPad) => {
let {
this.mindMap.event.on('mousewheel', (e, dirs, event, isTouchPad) => {
const {
customHandleMousewheel,
mousewheelAction,
mouseScaleCenterUseMousePosition,
@@ -71,55 +71,61 @@ class View {
) {
return customHandleMousewheel(e)
}
// 鼠标滚轮事件控制缩放
// 1.鼠标滚轮事件控制缩放
if (mousewheelAction === CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM || e.ctrlKey) {
if (disableMouseWheelZoom) return
const { x: clientX, y: clientY } = this.mindMap.toPos(
e.clientX,
e.clientY
)
let cx = mouseScaleCenterUseMousePosition ? clientX : undefined
let cy = mouseScaleCenterUseMousePosition ? clientY : undefined
switch (dir) {
const cx = mouseScaleCenterUseMousePosition ? clientX : undefined
const cy = mouseScaleCenterUseMousePosition ? clientY : undefined
// 如果来自触控板,那么过滤掉左右的移动
if (
isTouchPad &&
(dirs.includes(CONSTANTS.DIR.LEFT) ||
dirs.includes(CONSTANTS.DIR.RIGHT))
) {
dirs = dirs.filter(dir => {
return ![CONSTANTS.DIR.LEFT, CONSTANTS.DIR.RIGHT].includes(dir)
})
}
switch (true) {
// 鼠标滚轮,向上和向左,都是缩小
case CONSTANTS.DIR.UP:
case CONSTANTS.DIR.LEFT:
case dirs.includes(CONSTANTS.DIR.UP || CONSTANTS.DIR.LEFT):
mousewheelZoomActionReverse
? this.enlarge(cx, cy, isTouchPad)
: this.narrow(cx, cy, isTouchPad)
break
// 鼠标滚轮,向下和向右,都是放大
case CONSTANTS.DIR.DOWN:
case CONSTANTS.DIR.RIGHT:
case dirs.includes(CONSTANTS.DIR.DOWN || CONSTANTS.DIR.RIGHT):
mousewheelZoomActionReverse
? this.narrow(cx, cy, isTouchPad)
: this.enlarge(cx, cy, isTouchPad)
break
}
} else {
// 鼠标滚轮事件控制画布移动
let step = mousewheelMoveStep
if (isTouchPad) {
step = 5
// 2.鼠标滚轮事件控制画布移动
const step = isTouchPad ? 5 : mousewheelMoveStep
let mx = 0
let my = 0
// 上移
if (dirs.includes(CONSTANTS.DIR.DOWN)) {
my = -step
}
switch (dir) {
// 上移
case CONSTANTS.DIR.DOWN:
this.translateY(-step)
break
// 下移
case CONSTANTS.DIR.UP:
this.translateY(step)
break
// 右移
case CONSTANTS.DIR.LEFT:
this.translateX(-step)
break
// 左移
case CONSTANTS.DIR.RIGHT:
this.translateX(step)
break
// 下移
if (dirs.includes(CONSTANTS.DIR.UP)) {
my = step
}
// 右移
if (dirs.includes(CONSTANTS.DIR.LEFT)) {
mx = step
}
// 左移
if (dirs.includes(CONSTANTS.DIR.RIGHT)) {
mx = -step
}
this.translateXY(mx, my)
}
})
}
@@ -188,6 +194,9 @@ class View {
// 应用变换
transform() {
try {
this.limitMindMapInCanvas()
} catch (error) {}
this.mindMap.draw.transform({
origin: [0, 0],
scale: this.scale,
@@ -254,18 +263,17 @@ class View {
// 适应画布大小
fit() {
let { fitPadding } = this.mindMap.opt
let draw = this.mindMap.draw
let origTransform = draw.transform()
let rect = draw.rbox()
let drawWidth = rect.width / origTransform.scaleX
let drawHeight = rect.height / origTransform.scaleY
let drawRatio = drawWidth / drawHeight
let { width: elWidth, height: elHeight } =
this.mindMap.elRect
const { fitPadding } = this.mindMap.opt
const draw = this.mindMap.draw
const origTransform = draw.transform()
const rect = draw.rbox()
const drawWidth = rect.width / origTransform.scaleX
const drawHeight = rect.height / origTransform.scaleY
const drawRatio = drawWidth / drawHeight
let { width: elWidth, height: elHeight } = this.mindMap.elRect
elWidth = elWidth - fitPadding * 2
elHeight = elHeight - fitPadding * 2
let elRatio = elWidth / elHeight
const elRatio = elWidth / elHeight
let newScale = 0
let flag = ''
if (drawWidth <= elWidth && drawHeight <= elHeight) {
@@ -286,7 +294,10 @@ class View {
newScale = newWidth / drawWidth
}
this.setScale(newScale)
let newRect = draw.rbox()
const newRect = draw.rbox()
// 需要考虑画布容器距浏览器窗口左上角的距离
newRect.x -= this.mindMap.elRect.left
newRect.y -= this.mindMap.elRect.top
let newX = 0
let newY = 0
if (flag === 1) {
@@ -301,6 +312,73 @@ class View {
}
this.translateXY(newX, newY)
}
// 将思维导图限制在画布内
limitMindMapInCanvas() {
const { isLimitMindMapInCanvasWhenHasScrollbar, isLimitMindMapInCanvas } =
this.mindMap.opt
// 如果注册了滚动条插件那么使用isLimitMindMapInCanvasWhenHasScrollbar配置
if (this.mindMap.scrollbar) {
if (!isLimitMindMapInCanvasWhenHasScrollbar) return
} else {
// 否则使用isLimitMindMapInCanvas配置
if (!isLimitMindMapInCanvas) return
}
let { scale, left, top, right, bottom } = this.getPositionLimit()
// 如果缩放值改变了
const scaleRatio = this.scale / scale
left *= scaleRatio
right *= scaleRatio
top *= scaleRatio
bottom *= scaleRatio
// 加上画布中心点距离
const centerX = this.mindMap.width / 2
const centerY = this.mindMap.height / 2
const scaleOffset = this.scale - 1
left -= scaleOffset * centerX
right -= scaleOffset * centerX
top -= scaleOffset * centerY
bottom -= scaleOffset * centerY
// 判断是否超出边界
if (this.x > left) {
this.x = left
}
if (this.x < right) {
this.x = right
}
if (this.y > top) {
this.y = top
}
if (this.y < bottom) {
this.y = bottom
}
}
// 计算图形四个方向的位置边界值
getPositionLimit() {
const { scaleX, scaleY } = this.mindMap.draw.transform()
const drawRect = this.mindMap.draw.rbox()
const rootRect = this.mindMap.renderer.root.group.rbox()
const rootCenterOffset = this.mindMap.renderer.layout.getRootCenterOffset(
rootRect.width,
rootRect.height
)
const left = rootRect.x - drawRect.x - rootCenterOffset.x * scaleX
const right = rootRect.x - drawRect.x2 - rootCenterOffset.x * scaleX
const top = rootRect.y - drawRect.y - rootCenterOffset.y * scaleY
const bottom = rootRect.y - drawRect.y2 - rootCenterOffset.y * scaleY
return {
scale: scaleX,
left,
right,
top,
bottom
}
}
}
export default View

View File

@@ -17,6 +17,8 @@ class Base {
// 根节点
this.root = null
this.lru = new Lru(this.mindMap.opt.maxNodeCacheCount)
// 当initRootNodePosition不为默认的值时根节点的位置距默认的配置时根节点距离的差值
this.rootNodeCenterOffset = null
}
// 计算节点位置
@@ -41,7 +43,7 @@ class Base {
cacheNode(uid, node) {
// 记录本次渲染时的节点
this.renderer.nodeCache[uid] = node
// 记录所有渲染的节点
// 缓存所有渲染的节点
this.lru.add(uid, node)
}
@@ -70,11 +72,12 @@ class Base {
// 创建节点实例
createNode(data, parent, isRoot, layerIndex) {
// 创建节点
const uid = data.data.uid
let newNode = null
// 数据上保存了节点引用,那么直接复用节点
if (data && data._node && !this.renderer.reRender) {
newNode = data._node
let isLayerTypeChange = this.checkIsLayerTypeChange(
const isLayerTypeChange = this.checkIsLayerTypeChange(
newNode.layerIndex,
layerIndex
)
@@ -87,43 +90,49 @@ class Base {
newNode.getSize()
newNode.needLayout = true
}
} else if (this.lru.has(data.data.uid) && !this.renderer.reRender) {
// 数据上没有保存节点引用但是通过uid找到了缓存的节点也可以复用
newNode = this.lru.get(data.data.uid)
} else if (
(this.lru.has(uid) || this.renderer.lastNodeCache[uid]) &&
!this.renderer.reRender
) {
// 节点数据上没有节点实例
// 但是通过uid在节点缓存池中找到了缓存的节点
// 或者在上一次渲染缓存对象中找到了节点
// 也可以直接复用
newNode = this.lru.get(uid) || this.renderer.lastNodeCache[uid]
// 保存该节点上一次的数据
let lastData = JSON.stringify(newNode.getData())
let isLayerTypeChange = this.checkIsLayerTypeChange(
const lastData = JSON.stringify(newNode.getData())
const isLayerTypeChange = this.checkIsLayerTypeChange(
newNode.layerIndex,
layerIndex
)
newNode.reset()
newNode.nodeData = newNode.handleData(data || {})
newNode.layerIndex = layerIndex
this.cacheNode(data.data.uid, newNode)
this.cacheNode(uid, newNode)
this.checkIsLayoutChangeRerenderExpandBtnPlaceholderRect(newNode)
data._node = newNode
// 主题或主题配置改变了需要重新计算节点大小和布局
let isResizeSource = this.checkIsNeedResizeSources()
const isResizeSource = this.checkIsNeedResizeSources()
// 节点数据改变了需要重新计算节点大小和布局
let isNodeDataChange = lastData !== JSON.stringify(data.data)
const isNodeDataChange = lastData !== JSON.stringify(data.data)
if (isResizeSource || isNodeDataChange || isLayerTypeChange) {
newNode.getSize()
newNode.needLayout = true
}
} else {
// 创建新节点
let uid = data.data.uid || createUid()
const newUid = uid || createUid()
newNode = new Node({
data,
uid,
uid: newUid,
renderer: this.renderer,
mindMap: this.mindMap,
draw: this.draw,
layerIndex
})
// uid保存到数据上为了节点复用
data.data.uid = uid
this.cacheNode(uid, newNode)
data.data.uid = newUid
this.cacheNode(newUid, newNode)
// 数据关联实际节点
data._node = newNode
if (data.data.isActive) {
@@ -161,17 +170,21 @@ class Base {
}
}
// 定位节点到画布中间
setNodeCenter(node) {
let { initRootNodePosition } = this.mindMap.opt
let { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION
if (
!initRootNodePosition ||
!Array.isArray(initRootNodePosition) ||
initRootNodePosition.length < 2
) {
initRootNodePosition = [CENTER, CENTER]
// 规范initRootNodePosition配置
formatInitRootNodePosition(pos) {
const { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION
if (!pos || !Array.isArray(pos) || pos.length < 2) {
pos = [CENTER, CENTER]
}
return pos
}
// 定位节点到画布中间
setNodeCenter(node, position) {
let { initRootNodePosition } = this.mindMap.opt
initRootNodePosition = this.formatInitRootNodePosition(
position || initRootNodePosition
)
node.left = this.formatPosition(
initRootNodePosition[0],
this.mindMap.width,
@@ -184,6 +197,42 @@ class Base {
)
}
// 当initRootNodePosition配置不为默认的['center','center']时,计算当前配置和默认配置情况下,根节点位置的差值
getRootCenterOffset(width, height) {
// 因为根节点的大小不会影响这个差值,所以计算一次就足够了
if (this.rootNodeCenterOffset) return this.rootNodeCenterOffset
let { initRootNodePosition } = this.mindMap.opt
const { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION
initRootNodePosition = this.formatInitRootNodePosition(initRootNodePosition)
if (
initRootNodePosition[0] === CENTER &&
initRootNodePosition[1] === CENTER
) {
// 如果initRootNodePosition是默认的那么不需要计算
this.rootNodeCenterOffset = {
x: 0,
y: 0
}
} else {
// 否则需要计算当前配置和默认配置的差值
const tmpNode = {
width: width,
height: height
}
const tmpNode2 = {
width: width,
height: height
}
this.setNodeCenter(tmpNode, [CENTER, CENTER])
this.setNodeCenter(tmpNode2)
this.rootNodeCenterOffset = {
x: tmpNode2.left - tmpNode.left,
y: tmpNode2.top - tmpNode.top
}
}
return this.rootNodeCenterOffset
}
// 更新子节点属性
updateChildren(children, prop, offset) {
children.forEach(item => {
@@ -394,6 +443,12 @@ class Base {
getNodeActChildrenLength(node) {
return node.nodeData.children && node.nodeData.children.length
}
// 设置连线样式
setLineStyle(style, line, path, childNode) {
line.plot(path)
style && style(line, childNode, true)
}
}
export default Base

View File

@@ -233,8 +233,7 @@ class CatalogOrganization extends Base {
`M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` +
nodeUseLineStylePath
// 竖线
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
minx = Math.min(minx, x1)
maxx = Math.max(maxx, x1)
@@ -302,8 +301,7 @@ class CatalogOrganization extends Base {
}`
: ''
path += nodeUseLineStylePath
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
// 竖线
if (len > 0) {

View File

@@ -300,8 +300,7 @@ class Fishbone extends Base {
// 水平线
if (node.layerIndex > 1) {
let path = `M ${x},${y} L ${item.left},${y}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
}
})
// 斜线

View File

@@ -181,8 +181,7 @@ class LogicalStructure extends Base {
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
x2 + nodeUseLineStyleOffset
},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -209,8 +208,7 @@ class LogicalStructure extends Base {
? ` L ${item.left + item.width},${y2}`
: ''
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -242,8 +240,7 @@ class LogicalStructure extends Base {
} else {
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
}
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}

View File

@@ -116,11 +116,7 @@ class MindMap extends Base {
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.getData('expand') &&
node.children &&
node.children.length
) {
if (node.getData('expand') && node.children && node.children.length) {
let marginY = this.getMarginY(layerIndex + 1)
let baseTop = node.top + node.height / 2 + marginY
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
@@ -247,8 +243,7 @@ class MindMap extends Base {
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${
x2 + nodeUseLineStyleOffset
},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -287,8 +282,7 @@ class MindMap extends Base {
}
}
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -332,8 +326,7 @@ class MindMap extends Base {
} else {
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
}
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -384,7 +377,8 @@ class MindMap extends Base {
x +
(isLeft ? -generalizationNodeMargin : generalizationNodeMargin) -
(isLeft ? item.generalizationNode.width : 0)
item.generalizationNode.top = top + (bottom - top - item.generalizationNode.height) / 2
item.generalizationNode.top =
top + (bottom - top - item.generalizationNode.height) / 2
})
}

View File

@@ -78,11 +78,7 @@ class OrganizationStructure extends Base {
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.getData('expand') &&
node.children &&
node.children.length
) {
if (node.getData('expand') && node.children && node.children.length) {
let marginX = this.getMarginY(layerIndex + 1)
// 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
@@ -175,8 +171,7 @@ class OrganizationStructure extends Base {
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
: ''
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
@@ -210,8 +205,7 @@ class OrganizationStructure extends Base {
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
: ''
let path = `M ${x2},${y1 + s1} L ${x2},${y2}` + nodeUseLineStylePath
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
minx = Math.min(x1, minx)
maxx = Math.max(x1, maxx)
@@ -261,9 +255,9 @@ class OrganizationStructure extends Base {
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
item.generalizationLine.plot(path)
item.generalizationNode.top = bottom + generalizationNodeMargin
item.generalizationNode.left = left + (right - left - item.generalizationNode.width) / 2
item.generalizationNode.left =
left + (right - left - item.generalizationNode.width) / 2
})
}
// 渲染展开收起按钮的隐藏占位元素

View File

@@ -245,8 +245,7 @@ class Timeline extends Base {
let x2 = item.left
let y = node.top + node.height / 2
let path = `M ${x1},${y} L ${x2},${y}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
prevBother = item
})
} else {
@@ -264,8 +263,7 @@ class Timeline extends Base {
}
// 水平线
let path = `M ${x},${y} L ${item.left},${y}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
// 竖线
if (len > 0) {

View File

@@ -246,8 +246,7 @@ class VerticalTimeline extends Base {
let y2 = item.top
let x = node.left + node.width / 2
let path = `M ${x},${y1} L ${x},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
prevBother = item
})
} else {
@@ -265,8 +264,7 @@ class VerticalTimeline extends Base {
L ${nodeRight + offset},${nodeYCenter}
L ${nodeRight + offset},${itemYCenter}
L ${itemLeft},${itemYCenter}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
} else {
let nodeLeft = node.left
@@ -281,8 +279,7 @@ class VerticalTimeline extends Base {
L ${nodeLeft - offset},${nodeYCenter}
L ${nodeLeft - offset},${itemYCenter}
L ${itemRight},${itemYCenter}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
})
}
}
@@ -306,8 +303,7 @@ class VerticalTimeline extends Base {
let y2 = item.top
let x = node.left + node.width / 2
let path = `M ${x},${y1} L ${x},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
prevBother = item
})
} else {
@@ -322,8 +318,7 @@ class VerticalTimeline extends Base {
: item.left
let y2 = item.top + item.height / 2
let path = `M ${x1},${y1} L ${x2},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
}
})
}
@@ -346,8 +341,7 @@ class VerticalTimeline extends Base {
let y2 = item.top
let x = node.left + node.width / 2
let path = `M ${x},${y1} L ${x},${y2}`
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
prevBother = item
})
} else {
@@ -362,8 +356,7 @@ class VerticalTimeline extends Base {
: item.left
let y2 = item.top + item.height / 2
let path = this.cubicBezierPath(x1, y1, x2, y2)
lines[index].plot(path)
style && style(lines[index], item)
this.setLineStyle(style, lines[index], path, item)
}
})
}

View File

@@ -59,43 +59,70 @@ class AssociativeLine {
// 监听事件
bindEvent() {
// 节点树渲染完毕后渲染连接线
this.renderAllLines = this.renderAllLines.bind(this)
this.onDrawClick = this.onDrawClick.bind(this)
this.onNodeClick = this.onNodeClick.bind(this)
this.removeLine = this.removeLine.bind(this)
this.addLine = this.addLine.bind(this)
this.onMousemove = this.onMousemove.bind(this)
this.onNodeDragging = this.onNodeDragging.bind(this)
this.onNodeDragend = this.onNodeDragend.bind(this)
this.onControlPointMouseup = this.onControlPointMouseup.bind(this)
// 节点树渲染完毕后渲染连接线
this.mindMap.on('node_tree_render_end', this.renderAllLines)
// 状态改变后重新渲染连接线
this.mindMap.on('data_change', this.renderAllLines)
// 监听画布和节点点击事件,用于清除当前激活的连接线
this.mindMap.on('draw_click', () => {
if (this.isControlPointMousedown) {
return
}
this.clearActiveLine()
})
this.mindMap.on('node_click', node => {
if (this.isCreatingLine) {
this.completeCreateLine(node)
} else {
this.clearActiveLine()
}
})
this.mindMap.on('draw_click', this.onDrawClick)
this.mindMap.on('node_click', this.onNodeClick)
// 注册删除快捷键
this.mindMap.keyCommand.addShortcut(
'Del|Backspace',
this.removeLine.bind(this)
)
this.mindMap.keyCommand.addShortcut('Del|Backspace', this.removeLine)
// 注册添加连接线的命令
this.mindMap.command.add('ADD_ASSOCIATIVE_LINE', this.addLine.bind(this))
this.mindMap.command.add('ADD_ASSOCIATIVE_LINE', this.addLine)
// 监听鼠标移动事件
this.mindMap.on('mousemove', this.onMousemove.bind(this))
this.mindMap.on('mousemove', this.onMousemove)
// 节点拖拽事件
this.mindMap.on('node_dragging', this.onNodeDragging.bind(this))
this.mindMap.on('node_dragend', this.onNodeDragend.bind(this))
this.mindMap.on('node_dragging', this.onNodeDragging)
this.mindMap.on('node_dragend', this.onNodeDragend)
// 拖拽控制点
this.mindMap.on('mouseup', this.onControlPointMouseup.bind(this))
this.mindMap.on('mouseup', this.onControlPointMouseup)
// 缩放事件
this.mindMap.on('scale', this.onScale)
}
// 解绑事件
unBindEvent() {
this.mindMap.off('node_tree_render_end', this.renderAllLines)
this.mindMap.off('data_change', this.renderAllLines)
this.mindMap.off('draw_click', this.onDrawClick)
this.mindMap.off('node_click', this.onNodeClick)
this.mindMap.keyCommand.removeShortcut('Del|Backspace', this.removeLine)
this.mindMap.command.remove('ADD_ASSOCIATIVE_LINE', this.addLine)
this.mindMap.off('mousemove', this.onMousemove)
this.mindMap.off('node_dragging', this.onNodeDragging)
this.mindMap.off('node_dragend', this.onNodeDragend)
this.mindMap.off('mouseup', this.onControlPointMouseup)
this.mindMap.off('scale', this.onScale)
}
// 画布点击事件
onDrawClick() {
if (this.isControlPointMousedown) {
return
}
this.clearActiveLine()
}
// 节点点击事件
onNodeClick(node) {
if (this.isCreatingLine) {
this.completeCreateLine(node)
} else {
this.clearActiveLine()
}
}
// 创建箭头
createMarker() {
return this.associativeLineDraw.marker(20, 20, add => {
@@ -544,6 +571,16 @@ class AssociativeLine {
this.associativeLineDraw.back() // 最底层
this.associativeLineDraw.forward() // 连线层上面
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()
}
}
AssociativeLine.instanceName = 'associativeLine'

View File

@@ -55,51 +55,68 @@ class Drag extends Base {
// 绑定事件
bindEvent() {
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
this.mindMap.on('node_mousedown', (node, e) => {
// 只读模式、不是鼠标左键按下、按下的是概要节点或根节点直接返回
if (
this.mindMap.opt.readonly ||
e.which !== 1 ||
node.isGeneralization ||
node.isRoot
) {
return
}
e.preventDefault()
this.isMousedown = true
// 记录鼠标按下时的节点
this.mousedownNode = node
// 记录鼠标按下的坐标
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x
this.mouseDownY = y
})
this.mindMap.on('mousemove', e => {
if (this.mindMap.opt.readonly || !this.isMousedown) {
return
}
e.preventDefault()
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x
this.mouseMoveY = y
// 还没开始移动时鼠标位移过小不认为是拖拽
if (
!this.isDragging &&
Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
Math.abs(y - this.mouseDownY) <= this.checkDragOffset
) {
return
}
this.mindMap.emit('node_dragging')
this.handleStartMove()
this.onMove(x, y, e)
})
this.onNodeMousedown = this.onNodeMousedown.bind(this)
this.onMousemove = this.onMousemove.bind(this)
this.onMouseup = this.onMouseup.bind(this)
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
this.mindMap.on('node_mousedown', this.onNodeMousedown)
this.mindMap.on('mousemove', this.onMousemove)
this.mindMap.on('node_mouseup', this.onMouseup)
this.mindMap.on('mouseup', this.onMouseup)
}
// 解绑事件
unBindEvent() {
this.mindMap.off('node_mousedown', this.onNodeMousedown)
this.mindMap.off('mousemove', this.onMousemove)
this.mindMap.off('node_mouseup', this.onMouseup)
this.mindMap.off('mouseup', this.onMouseup)
}
// 节点鼠标按下事件
onNodeMousedown(node, e) {
// 只读模式、不是鼠标左键按下、按下的是概要节点或根节点直接返回
if (
this.mindMap.opt.readonly ||
e.which !== 1 ||
node.isGeneralization ||
node.isRoot
) {
return
}
e.preventDefault()
this.isMousedown = true
// 记录鼠标按下时的节点
this.mousedownNode = node
// 记录鼠标按下的坐标
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x
this.mouseDownY = y
}
// 鼠标移动事件
onMousemove(e) {
if (this.mindMap.opt.readonly || !this.isMousedown) {
return
}
e.preventDefault()
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x
this.mouseMoveY = y
// 还没开始移动时鼠标位移过小不认为是拖拽
if (
!this.isDragging &&
Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
Math.abs(y - this.mouseDownY) <= this.checkDragOffset
) {
return
}
this.mindMap.emit('node_dragging', this.mousedownNode)
this.handleStartMove()
this.onMove(x, y, e)
}
// 鼠标松开事件
onMouseup(e) {
if (!this.isMousedown) {
@@ -685,6 +702,16 @@ class Drag extends Base {
return item.uid === node.uid || item.isAncestor(node)
})
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()
}
}
Drag.instanceName = 'drag'

View File

@@ -9,7 +9,7 @@ import {
import { SVG } from '@svgdotjs/svg.js'
import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas'
import { transformToMarkdown } from '../parse/toMarkdown'
import { a4Size, ERROR_TYPES } from '../constants/constant'
import { ERROR_TYPES } from '../constants/constant'
// 导出插件
class Export {
@@ -92,14 +92,7 @@ class Export {
}
// svg转png
svgToPng(
svgSrc,
transparent,
checkRotate = () => {
return false
},
compress
) {
svgToPng(svgSrc, transparent) {
return new Promise((resolve, reject) => {
const img = new Image()
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
@@ -113,36 +106,27 @@ class Export {
)
let imgWidth = img.width
let imgHeight = img.height
// 压缩图片
if (compress) {
const compressedSize = resizeImgSize(
imgWidth,
imgHeight,
compress.width,
compress.height
)
imgWidth = compressedSize[0]
imgHeight = compressedSize[1]
}
// 如果宽比高长那么旋转90度
const needRotate = checkRotate(imgWidth, imgHeight)
if (needRotate) {
canvas.width = imgHeight * dpr
canvas.height = imgWidth * dpr
canvas.style.width = imgHeight + 'px'
canvas.style.height = imgWidth + 'px'
} else {
canvas.width = imgWidth * dpr
canvas.height = imgHeight * dpr
canvas.style.width = imgWidth + 'px'
canvas.style.height = imgHeight + 'px'
// 检查是否超出canvas支持的像素上限
const maxSize = 16384 / dpr
const maxArea = maxSize * maxSize
if (imgWidth * imgHeight > maxArea) {
let newWidth = null
let newHeight = null
if (imgWidth > maxSize) {
newWidth = maxArea / imgHeight
} else if (imgHeight > maxSize) {
newHeight = maxArea / imgWidth
}
const res = resizeImgSize(imgWidth, imgHeight, newWidth, newHeight)
imgWidth = res[0]
imgHeight = res[1]
}
canvas.width = imgWidth * dpr
canvas.height = imgHeight * dpr
canvas.style.width = imgWidth + 'px'
canvas.style.height = imgHeight + 'px'
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
if (needRotate) {
ctx.rotate(0.5 * Math.PI)
ctx.translate(0, -imgHeight)
}
// 绘制背景
if (!transparent) {
await this.drawBackgroundToCanvas(ctx, imgWidth, imgHeight)
@@ -232,31 +216,20 @@ class Export {
* 方法1.把svg的图片都转化成data:url格式再转换
* 方法2.把svg的图片提取出来再挨个绘制到canvas里最后一起转换
*/
async png(name, transparent = false, checkRotate, compress) {
async png(name, transparent = false) {
const { str } = await this.getSvgData()
const svgUrl = await this.fixSvgStrAndToBlob(str)
// 绘制到canvas上
const res = await this.svgToPng(svgUrl, transparent, checkRotate, compress)
const res = await this.svgToPng(svgUrl, transparent)
return res
}
// 导出为pdf
async pdf(name, useMultiPageExport, maxImageWidth) {
async pdf(name, transparent = false) {
if (!this.mindMap.doExportPDF) {
throw new Error('请注册ExportPDF插件')
}
const img = await this.png(
'',
false,
(width, height) => {
if (width <= a4Size.width && height && a4Size.height) return false
return width / height > 1
},
{
width: maxImageWidth || a4Size.width * 2
}
)
await this.mindMap.doExportPDF.pdf(name, img, useMultiPageExport)
const img = await this.png(name, transparent)
await this.mindMap.doExportPDF.pdf(name, img)
}
// 导出为xmind

View File

@@ -1,5 +1,4 @@
import JsPDF from '../utils/jspdf'
import { a4Size } from '../constants/constant'
// 导出PDF插件需要通过Export插件使用
class ExportPDF {
@@ -9,104 +8,20 @@ class ExportPDF {
}
// 导出为pdf
async pdf(name, img, useMultiPageExport = false) {
if (useMultiPageExport) {
await this.multiPageExport(name, img)
} else {
await this.onePageExport(name, img)
}
}
// 单页导出
onePageExport(name, img) {
async pdf(name, img) {
return new Promise((resolve, reject) => {
let pdf = new JsPDF({
unit: 'pt',
format: 'a4',
compress: true
})
let a4Ratio = a4Size.width / a4Size.height
let image = new Image()
const image = new Image()
image.onload = () => {
let imageWidth = image.width
let imageHeight = image.height
let imageRatio = imageWidth / imageHeight
let w, h
if (imageWidth <= a4Size.width && imageHeight <= a4Size.height) {
// 使用图片原始宽高
w = imageWidth
h = imageHeight
} else if (a4Ratio > imageRatio) {
// 以a4Height为高度缩放图片宽度
w = imageRatio * a4Size.height
h = a4Size.height
} else {
// 以a4Width为宽度缩放图片高度
w = a4Size.width
h = a4Size.width / imageRatio
}
pdf.addImage(
img,
'PNG',
(a4Size.width - w) / 2,
(a4Size.height - h) / 2,
w,
h
)
pdf.save(name)
resolve()
}
image.onerror = e => {
reject(e)
}
image.src = img
})
}
// 多页导出
multiPageExport(name, img) {
return new Promise((resolve, reject) => {
let image = new Image()
image.onload = () => {
let imageWidth = image.width
let imageHeight = image.height
// 一页pdf显示高度
let pageHeight = (imageWidth / a4Size.width) * a4Size.height
// 未生成pdf的高度
let leftHeight = imageHeight
// 偏移
let position = 0
// a4纸的尺寸[595.28,841.89]图片在pdf中图片的宽高
let imgWidth = a4Size.width
let imgHeight = (a4Size.width / imageWidth) * imageHeight
let pdf = new JsPDF({
unit: 'pt',
format: 'a4',
compress: true
const imageWidth = image.width
const imageHeight = image.height
const pdf = new JsPDF({
unit: 'px',
format: [imageWidth, imageHeight],
compress: true,
hotfixes: ['px_scaling'],
orientation: imageWidth > imageHeight ? 'landscape' : 'portrait'
})
// 有两个高度需要区分一个是图片的实际高度和生成pdf的页面高度(841.89)
// 当内容未超过pdf一页显示的范围无需分页
if (leftHeight < pageHeight) {
pdf.addImage(
img,
'PNG',
(a4Size.width - imgWidth) / 2,
(a4Size.height - imgHeight) / 2,
imgWidth,
imgHeight
)
} else {
// 分页
while (leftHeight > 0) {
pdf.addImage(img, 'PNG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= a4Size.height
// 避免添加空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.addImage(img, 'PNG', 0, 0, imageWidth, imageHeight)
pdf.save(name)
resolve()
}

View File

@@ -37,7 +37,7 @@ class Formula {
// 给指定的节点插入指定公式
insertFormulaToNode(node, formula) {
let richTextPlugin = this.mindMap.richText
richTextPlugin.showEditText(node)
richTextPlugin.showEditText({ node })
richTextPlugin.quill.insertEmbed(
richTextPlugin.quill.getLength() - 1,
'formula',

View File

@@ -7,19 +7,61 @@ class KeyboardNavigation {
constructor(opt) {
this.opt = opt
this.mindMap = opt.mindMap
this.onKeyup = this.onKeyup.bind(this)
this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.LEFT, () => {
this.onKeyup(CONSTANTS.KEY_DIR.LEFT)
})
this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.UP, () => {
this.onKeyup(CONSTANTS.KEY_DIR.UP)
})
this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.RIGHT, () => {
this.onKeyup(CONSTANTS.KEY_DIR.RIGHT)
})
this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.DOWN, () => {
this.onKeyup(CONSTANTS.KEY_DIR.DOWN)
})
this.addShortcut()
}
addShortcut() {
this.onLeftKeyUp = this.onLeftKeyUp.bind(this)
this.onUpKeyUp = this.onUpKeyUp.bind(this)
this.onRightKeyUp = this.onRightKeyUp.bind(this)
this.onDownKeyUp = this.onDownKeyUp.bind(this)
this.mindMap.keyCommand.addShortcut(
CONSTANTS.KEY_DIR.LEFT,
this.onLeftKeyUp
)
this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.UP, this.onUpKeyUp)
this.mindMap.keyCommand.addShortcut(
CONSTANTS.KEY_DIR.RIGHT,
this.onRightKeyUp
)
this.mindMap.keyCommand.addShortcut(
CONSTANTS.KEY_DIR.DOWN,
this.onDownKeyUp
)
}
removeShortcut() {
this.mindMap.keyCommand.removeShortcut(
CONSTANTS.KEY_DIR.LEFT,
this.onLeftKeyUp
)
this.mindMap.keyCommand.removeShortcut(CONSTANTS.KEY_DIR.UP, this.onUpKeyUp)
this.mindMap.keyCommand.removeShortcut(
CONSTANTS.KEY_DIR.RIGHT,
this.onRightKeyUp
)
this.mindMap.keyCommand.removeShortcut(
CONSTANTS.KEY_DIR.DOWN,
this.onDownKeyUp
)
}
onLeftKeyUp() {
this.onKeyup(CONSTANTS.KEY_DIR.LEFT)
}
onUpKeyUp() {
this.onKeyup(CONSTANTS.KEY_DIR.UP)
}
onRightKeyUp() {
this.onKeyup(CONSTANTS.KEY_DIR.RIGHT)
}
onDownKeyUp() {
this.onKeyup(CONSTANTS.KEY_DIR.DOWN)
}
// 处理按键事件
@@ -228,6 +270,16 @@ class KeyboardNavigation {
y: (top + bottom) / 2
}
}
// 插件被移除前做的事情
beforePluginRemove() {
this.removeShortcut()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.removeShortcut()
}
}
KeyboardNavigation.instanceName = 'keyboardNavigation'

View File

@@ -96,8 +96,13 @@ class RichText {
border: none;
}
.smm-richtext-node-wrap {
word-break: break-all;
}
.smm-richtext-node-wrap p {
font-family: auto;
}
.smm-richtext-node-edit-wrap p {
@@ -255,8 +260,7 @@ class RichText {
this.textEditNode.innerHTML = this.cacheEditingText || html
} else {
// 已经是富文本
this.textEditNode.innerHTML =
this.cacheEditingText || nodeText
this.textEditNode.innerHTML = this.cacheEditingText || nodeText
}
this.initQuillEditor()
document.querySelector('.ql-editor').style.minHeight = originHeight + 'px'
@@ -372,6 +376,8 @@ class RichText {
rectInfo,
formatInfo
)
} else {
this.mindMap.emit('rich_text_selection_change', false, null, null)
}
})
this.quill.on('text-change', () => {

View File

@@ -171,6 +171,10 @@ class Scrollbar {
const t = this.mindMap.draw.transform()
const drawRect = this.mindMap.draw.rbox()
const rootRect = this.mindMap.renderer.root.group.rbox()
const rootCenterOffset = this.mindMap.renderer.layout.getRootCenterOffset(
rootRect.width,
rootRect.height
)
if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
// 滚动条新位置
let oy = offset
@@ -178,7 +182,7 @@ class Scrollbar {
if (oy <= 0) {
oy = 0
}
let max =
const max =
((100 - scrollbarData.vertical.height) / 100) *
this.scrollbarWrapSize.height
if (oy >= max) {
@@ -193,7 +197,12 @@ class Scrollbar {
// 内边距
const paddingY = this.mindMap.height / 2
// 图形新位置
let chartTop = oyPx + yOffset - paddingY * t.scaleY + paddingY
const chartTop =
oyPx +
yOffset -
paddingY * t.scaleY +
paddingY -
rootCenterOffset.y * t.scaleY
this.mindMap.view.translateYTo(chartTop)
this.emitEvent({
horizontal: scrollbarData.horizontal,
@@ -209,7 +218,7 @@ class Scrollbar {
if (ox <= 0) {
ox = 0
}
let max =
const max =
((100 - scrollbarData.horizontal.width) / 100) *
this.scrollbarWrapSize.width
if (ox >= max) {
@@ -217,14 +226,19 @@ class Scrollbar {
}
// 转换成百分比
const oxPercentage = (ox / this.scrollbarWrapSize.width) * 100
// 转换成相对于图形度的距离
// 转换成相对于图形度的距离
const oxPx = (-oxPercentage / 100) * this.chartWidth
// 节点中心点到图形最左边的距离
const xOffset = rootRect.x - drawRect.x
// 内边距
const paddingX = this.mindMap.width / 2
// 图形新位置
let chartLeft = oxPx + xOffset - paddingX * t.scaleX + paddingX
const chartLeft =
oxPx +
xOffset -
paddingX * t.scaleX +
paddingX -
rootCenterOffset.x * t.scaleX
this.mindMap.view.translateXTo(chartLeft)
this.emitEvent({
vertical: scrollbarData.vertical,
@@ -247,6 +261,11 @@ class Scrollbar {
this.updateMindMapView(type, offset)
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()

View File

@@ -22,10 +22,19 @@ class Search {
this.notResetSearchText = false
// 是否自动跳转下一个匹配节点
this.isJumpNext = false
this.bindEvent()
}
bindEvent() {
this.onDataChange = this.onDataChange.bind(this)
this.mindMap.on('data_change', this.onDataChange)
}
unBindEvent() {
this.mindMap.off('data_change', this.onDataChange)
}
// 节点数据改变了,需要重新搜索
onDataChange() {
if (this.isJumpNext) {
@@ -177,6 +186,16 @@ class Search {
total: this.matchNodeList.length
})
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()
}
}
Search.instanceName = 'search'

View File

@@ -18,82 +18,99 @@ class Select {
// 绑定事件
bindEvent() {
this.checkInNodes = throttle(this.checkInNodes, 300, this)
this.mindMap.on('mousedown', e => {
if (this.mindMap.opt.readonly) {
return
}
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
if (
!e.ctrlKey &&
(useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3)
) {
return
}
e.preventDefault()
this.isMousedown = true
this.cacheActiveList = [...this.mindMap.renderer.activeNodeList]
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x
this.mouseDownY = y
this.createRect(x, y)
})
this.mindMap.on('mousemove', e => {
if (this.mindMap.opt.readonly) {
return
}
if (!this.isMousedown) {
return
}
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x
this.mouseMoveY = y
if (
Math.abs(x - this.mouseDownX) <= 10 &&
Math.abs(y - this.mouseDownY) <= 10
) {
return
}
this.clearAutoMoveTimer()
this.onMove(
e.clientX,
e.clientY,
() => {
this.isSelecting = true
// 绘制矩形
this.rect.plot([
[this.mouseDownX, this.mouseDownY],
[this.mouseMoveX, this.mouseDownY],
[this.mouseMoveX, this.mouseMoveY],
[this.mouseDownX, this.mouseMoveY]
])
this.checkInNodes()
},
(dir, step) => {
switch (dir) {
case 'left':
this.mouseDownX += step
break
case 'top':
this.mouseDownY += step
break
case 'right':
this.mouseDownX -= step
break
case 'bottom':
this.mouseDownY -= step
break
default:
break
}
}
)
})
this.onMousedown = this.onMousedown.bind(this)
this.onMousemove = this.onMousemove.bind(this)
this.onMouseup = this.onMouseup.bind(this)
this.checkInNodes = throttle(this.checkInNodes, 300, this)
this.mindMap.on('mousedown', this.onMousedown)
this.mindMap.on('mousemove', this.onMousemove)
this.mindMap.on('mouseup', this.onMouseup)
this.mindMap.on('node_mouseup', this.onMouseup)
}
// 解绑事件
unBindEvent() {
this.mindMap.off('mousedown', this.onMousedown)
this.mindMap.off('mousemove', this.onMousemove)
this.mindMap.off('mouseup', this.onMouseup)
this.mindMap.off('node_mouseup', this.onMouseup)
}
// 鼠标按下
onMousedown(e) {
if (this.mindMap.opt.readonly) {
return
}
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
if (
!e.ctrlKey &&
(useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3)
) {
return
}
e.preventDefault()
this.isMousedown = true
this.cacheActiveList = [...this.mindMap.renderer.activeNodeList]
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x
this.mouseDownY = y
this.createRect(x, y)
}
// 鼠标移动
onMousemove(e) {
if (this.mindMap.opt.readonly) {
return
}
if (!this.isMousedown) {
return
}
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x
this.mouseMoveY = y
if (
Math.abs(x - this.mouseDownX) <= 10 &&
Math.abs(y - this.mouseDownY) <= 10
) {
return
}
this.clearAutoMoveTimer()
this.onMove(
e.clientX,
e.clientY,
() => {
this.isSelecting = true
// 绘制矩形
this.rect.plot([
[this.mouseDownX, this.mouseDownY],
[this.mouseMoveX, this.mouseDownY],
[this.mouseMoveX, this.mouseMoveY],
[this.mouseDownX, this.mouseMoveY]
])
this.checkInNodes()
},
(dir, step) => {
switch (dir) {
case 'left':
this.mouseDownX += step
break
case 'top':
this.mouseDownY += step
break
case 'right':
this.mouseDownX -= step
break
case 'bottom':
this.mouseDownY -= step
break
default:
break
}
}
)
}
// 结束框选
onMouseup() {
if (this.mindMap.opt.readonly) {
@@ -233,6 +250,16 @@ class Select {
hasSelectRange() {
return this.isSelecting
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.unBindEvent()
}
}
Select.instanceName = 'select'

View File

@@ -12,6 +12,7 @@ class Watermark {
this.text = '' // 水印文字
this.textStyle = {} // 水印文字样式
this.watermarkDraw = null // 容器
this.isInExport = false // 是否是在导出过程中
this.maxLong = this.getMaxLong()
this.updateWatermark(this.mindMap.opt.watermarkConfig || {})
this.bindEvent()
@@ -72,11 +73,18 @@ class Watermark {
this.textStyle = Object.assign(this.textStyle, textStyle || {})
}
// 清除水印
clear() {
if (this.watermarkDraw) this.watermarkDraw.clear()
}
// 绘制水印
// 非精确绘制,会绘制一些超出可视区域的水印
draw() {
// 清空之前的水印
if (this.watermarkDraw) this.watermarkDraw.clear()
this.clear()
// 如果是仅导出需要水印,那么非导出中不渲染
const { onlyExport } = this.mindMap.opt.watermarkConfig
if (onlyExport && !this.isInExport) return
// 如果没有水印数据,那么水印容器也删除掉
if (!this.hasWatermark()) {
this.removeContainer()

View File

@@ -20,6 +20,8 @@ export default {
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线curve、直线straight、直连direct
// 曲线连接时,根节点和其他节点的连接线样式保持统一,默认根节点为 ( 型,其他节点为 { 型设为true后都为 { 型
rootLineKeepSameInCurve: true,
// 连线尾部是否显示标记,目前只支持箭头
showLineMarker: false,
// 概要连线的粗细
generalizationLineWidth: 1,
// 概要连线的颜色
@@ -159,7 +161,8 @@ const nodeSizeIndependenceList = [
'backgroundRepeat',
'backgroundPosition',
'backgroundSize',
'rootLineKeepSameInCurve'
'rootLineKeepSameInCurve',
'showLineMarker'
]
export const checkIsNodeSizeIndependenceConfig = config => {
let keys = Object.keys(config)

View File

@@ -7,16 +7,24 @@ export default class Lru {
}
add(key, value) {
const isExist = this.has(key)
// 如果该key之前不存在并且现在数量已经超出最大值则不再继续添加
if (!isExist && this.size >= this.max) {
return false
}
// 已经存在则可以更新,因为不影响数量
// 如果该key是否已经存在则先删除
this.delete(key)
// 添加
this.pool.set(key, value)
this.size++
// 如果数量超出最大值,则删除最早的
if (this.size > this.max) {
let keys = this.pool.keys()
let last = keys.next()
this.delete(last.value)
}
// 删除最早的没啥意义详见https://github.com/wanglin2/mind-map/issues/467
// if (this.size > this.max) {
// let keys = this.pool.keys()
// let last = keys.next()
// this.delete(last.value)
// }
return true
}
delete(key) {
@@ -35,4 +43,9 @@ export default class Lru {
return this.pool.get(key)
}
}
clear() {
this.size = 0
this.pool = new Map()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -11,6 +11,7 @@ export default {
width: 'Width',
style: 'Style',
lineOfOutline: 'Line of outline',
showArrow: 'Is show arrow',
nodePadding: 'Node padding',
nodeMargin: 'Node margin',
horizontal: 'Horizontal',
@@ -27,6 +28,7 @@ export default {
enableFreeDrag: 'Enable node free drag',
watermark: 'Watermark',
showWatermark: 'Is show watermark',
onlyExport: 'Only export',
watermarkDefaultText: 'Watermark text',
watermarkText: 'Watermark text',
watermarkTextColor: 'Text color',

View File

@@ -11,6 +11,7 @@ export default {
width: '粗细',
style: '风格',
lineOfOutline: '概要的连线',
showArrow: '是否显示箭头',
nodePadding: '节点内边距',
nodeMargin: '节点外边距',
horizontal: '水平',
@@ -28,6 +29,7 @@ export default {
watermark: '水印',
showWatermark: '是否显示水印',
watermarkDefaultText: '水印文字',
onlyExport: '是否仅在导出时显示',
watermarkText: '水印文字',
watermarkTextColor: '文字颜色',
watermarkLineSpacing: '水印行间距',

View File

@@ -18,6 +18,7 @@ let APIList = [
'constructor',
'node',
'render',
'textEdit',
'view',
'keyCommand',
'command',

View File

@@ -1,5 +1,67 @@
# Changelog
## 0.9.2
Fix:
> 1.Fix the issue of no line breaks when node text contains consecutive numbers or letters.
>
> 2.Fix the issue of duplicate node drawing when importing files with the same UID as existing nodes on the current canvas.
>
> 3.Fix the issue of duplicate rendering of nodes caused by forward and backward when the number of nodes exceeds the maximum number of cache pools.
>
> 4.Fix the issue of the canvas moving in the opposite direction when scrolling horizontally with the mouse or touchpad.
>
> 5.Fix the issue where the mouse in flag is not reset when a node is destroyed.
>
> 6.Fix the issue of incorrect position calculation in the scrollbar plugin when the 'initRootNodePosition' configuration is not set to the default '[center, center]'.
>
> 7.Fix the issue where dragging the canvas cannot stop when the mouse is released on the node.
>
> 8.Fix the issue of errors in the position calculated by the view. fit method when the canvas container is not 0 from the top left corner of the browser window.
>
> 9.Fix the issue where the watermark in the exported image does not fully cover the entire image when there are a large number of nodes.
>
> 10.Fix the issue of inserting formula errors.
>
> 11.Fix the issue of losing the selected text status when the mouse moves out of the editing box while selecting text in the node text editing state.
>
> 12.When repairing node rich text editing, Fix the issue 'rich_text_selection_change' event is not triggered when the text selection range is 'null'.
>
> 13.Fix the issue of no 'node' instance in the 'node_dragging' event callback.
>
> 14.Fix the issue of too many nodes and the canvas size being too large to export PNG.
New:
> 1.Modify the mousewheel event, change the dir flag to dirs, support storing multiple directions, and optimize the dual finger movement operation of the touchpad.
>
> 2.The TextEdit class adds the isShowTextEdit method to determine whether the current node is in an editing state.
>
> 3.Change the paste method of the render class to support pasting clipboard data.
>
> 4.Add a configuration option to restrict mind map graphics within the canvas.
>
> 5.When registering the scrollbar plugin, it supports configuring whether to restrict the mind map within the canvas.
>
> 6.Folding all nodes will move the mind map root node to the center of the canvas.
>
> 7.Support the configuration option of displaying watermarks only during export.
>
> 8.When pasting images from the clipboard at a node, custom processing functions are supported to upload the images to your server.
>
> 9.Refactoring the export logic of the PDF, the exported PDF size is no longer a fixed A4, but the size of the mind map, while deleting the configuration for pagination export.
>
> 10.Node connections support displaying arrows as a field for the theme.
>
> 11.The maximum number of historical records is adjusted to 500 by default.
Demo
> 1.Support configuration to display watermarks only during export.
>
> 2.Basic style configuration line supports displaying arrows.
## 0.9.1-fix.2
Fix:

View File

@@ -1,6 +1,43 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.9.2</h2>
<p>Fix:</p>
<blockquote>
<p>1.Fix the issue of no line breaks when node text contains consecutive numbers or letters.</p>
<p>2.Fix the issue of duplicate node drawing when importing files with the same UID as existing nodes on the current canvas.</p>
<p>3.Fix the issue of duplicate rendering of nodes caused by forward and backward when the number of nodes exceeds the maximum number of cache pools.</p>
<p>4.Fix the issue of the canvas moving in the opposite direction when scrolling horizontally with the mouse or touchpad.</p>
<p>5.Fix the issue where the mouse in flag is not reset when a node is destroyed.</p>
<p>6.Fix the issue of incorrect position calculation in the scrollbar plugin when the 'initRootNodePosition' configuration is not set to the default '[center, center]'.</p>
<p>7.Fix the issue where dragging the canvas cannot stop when the mouse is released on the node.</p>
<p>8.Fix the issue of errors in the position calculated by the view. fit method when the canvas container is not 0 from the top left corner of the browser window.</p>
<p>9.Fix the issue where the watermark in the exported image does not fully cover the entire image when there are a large number of nodes.</p>
<p>10.Fix the issue of inserting formula errors.</p>
<p>11.Fix the issue of losing the selected text status when the mouse moves out of the editing box while selecting text in the node text editing state.</p>
<p>12.When repairing node rich text editing, Fix the issue 'rich_text_selection_change' event is not triggered when the text selection range is 'null'.</p>
<p>13.Fix the issue of no 'node' instance in the 'node_dragging' event callback.</p>
<p>14.Fix the issue of too many nodes and the canvas size being too large to export PNG.</p>
</blockquote>
<p>New:</p>
<blockquote>
<p>1.Modify the mousewheel event, change the dir flag to dirs, support storing multiple directions, and optimize the dual finger movement operation of the touchpad.</p>
<p>2.The TextEdit class adds the isShowTextEdit method to determine whether the current node is in an editing state.</p>
<p>3.Change the paste method of the render class to support pasting clipboard data.</p>
<p>4.Add a configuration option to restrict mind map graphics within the canvas.</p>
<p>5.When registering the scrollbar plugin, it supports configuring whether to restrict the mind map within the canvas.</p>
<p>6.Folding all nodes will move the mind map root node to the center of the canvas.</p>
<p>7.Support the configuration option of displaying watermarks only during export.</p>
<p>8.When pasting images from the clipboard at a node, custom processing functions are supported to upload the images to your server.</p>
<p>9.Refactoring the export logic of the PDF, the exported PDF size is no longer a fixed A4, but the size of the mind map, while deleting the configuration for pagination export.</p>
<p>10.Node connections support displaying arrows as a field for the theme.</p>
<p>11.The maximum number of historical records is adjusted to 500 by default.</p>
</blockquote>
<p>Demo</p>
<blockquote>
<p>1.Support configuration to display watermarks only during export.</p>
<p>2.Basic style configuration line supports displaying arrows.</p>
</blockquote>
<h2>0.9.1-fix.2</h2>
<p>Fix:</p>
<blockquote>

View File

@@ -61,7 +61,7 @@ const mindMap = new MindMap({
| 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 | |
| maxHistoryCountv0.5.6+ | Number | 1000 | | Maximum number of history records |
| maxHistoryCountv0.5.6+ | Number | 1000v0.9.2+ changed 500 | | Maximum number of history records |
| 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 | |
@@ -105,6 +105,9 @@ const mindMap = new MindMap({
| 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 |
### Data structure
@@ -156,6 +159,7 @@ If you want to add custom fields, you can add them to the same level as 'data' a
| 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
@@ -381,7 +385,7 @@ Listen to an event. Event list:
| mousemove | el element mouse move event | e (event object), this (Event event class instance) |
| drag | If it is a drag event while holding down the left button | e (event object), this (Event event class instance) |
| mouseup | el element mouse up event | e (event object), this (Event event class instance) |
| mousewheel | Mouse scroll event | e (event object), dir (up or down scroll), this (Event event class instance) 、isTouchPadv0.6.1+, Is it an event triggered by the touchpad |
| mousewheel | Mouse scroll event | e (event object), dir (up or down scroll. v0.9.2+ changed to dirs, array type, which supports saving multiple directions simultaneously), this (Event event class instance) 、isTouchPadv0.6.1+, Is it an event triggered by the touchpad |
| contextmenu | svg canvas right mouse button menu event | e (event object) |
| node_click | Node click event | this (node instance), e (event object) |
| node_mousedown | Node mouse down event | this (node instance), e (event object) |
@@ -414,6 +418,8 @@ Listen to an event. Event list:
| set_datav0.7.3+ | Triggered when the setData method is called to dynamically set mind map data | dataNew Mind Map Data |
| resizev0.8.0+ | Triggered after the container size changes, actually when the 'resize' method of the mind map instance is called | |
| beforeDestroyv0.9.0+ | Triggered before destroying the mind map, i.e. triggered by calling the destroy method | |
| body_mousedownv0.9.2+ | Mousedown event of document.body | eevent object |
| body_click | Click event of document.body | eevent object |
### emit(event, ...args)
@@ -507,7 +513,7 @@ redo. All commands are as follows:
| EXPAND_ALL | Expand all nodes | |
| UNEXPAND_ALL | Collapse all nodes | |
| UNEXPAND_TO_LEVEL (v0.2.8+) | Expand to a specified level | level (the level to expand to, 1, 2, 3...) |
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object. Note that this command will not trigger view updates | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
| SET_NODE_TEXT | Set node text | node (the node to set), text (the new text for the node), richTextv0.4.0+, If you want to set a rich text character, you need to set it to `true`、resetRichTextv0.6.10+Do you want to reset rich text? The default is false. If true is passed, the style of the rich text node will be reset |
| SET_NODE_IMAGE | Set Node Image | node (node to set), imgData (object, image information, structured as: `{url, title, width, height}`, the width and height of the image must be passed) |
| SET_NODE_ICON | Set Node Icon | node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the [icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js) file, icon name is type_name, such as ['priority_1']) |

View File

@@ -290,7 +290,7 @@
<tr>
<td>maxHistoryCountv0.5.6+</td>
<td>Number</td>
<td>1000</td>
<td>1000v0.9.2+ changed 500</td>
<td></td>
<td>Maximum number of history records</td>
</tr>
@@ -595,6 +595,27 @@
<td>Image address, the default image displayed when node image loading fails</td>
<td></td>
</tr>
<tr>
<td>handleNodePasteImgv0.9.2+</td>
<td>null or Function</td>
<td>null</td>
<td>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} }</td>
<td></td>
</tr>
<tr>
<td>isLimitMindMapInCanvasv0.9.2+</td>
<td>Boolean</td>
<td>false</td>
<td>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</td>
<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>
</tbody>
</table>
<h3>Data structure</h3>
@@ -674,6 +695,12 @@
<td>{color: '#999', opacity: 0.5, fontSize: 14}</td>
<td>Watermark text style</td>
</tr>
<tr>
<td>onlyExportv0.9.2+</td>
<td>Boolean</td>
<td>false</td>
<td>Is only add watermarks during export</td>
</tr>
</tbody>
</table>
<h3>Icon Configuration</h3>
@@ -910,7 +937,7 @@ poor performance and should be used sparingly.</p>
<tr>
<td>mousewheel</td>
<td>Mouse scroll event</td>
<td>e (event object), dir (up or down scroll), this (Event event class instance) 、isTouchPadv0.6.1+, Is it an event triggered by the touchpad</td>
<td>e (event object), dir (up or down scroll. v0.9.2+ changed to dirs, array type, which supports saving multiple directions simultaneously), this (Event event class instance) 、isTouchPadv0.6.1+, Is it an event triggered by the touchpad</td>
</tr>
<tr>
<td>contextmenu</td>
@@ -1072,6 +1099,16 @@ poor performance and should be used sparingly.</p>
<td>Triggered before destroying the mind map, i.e. triggered by calling the destroy method</td>
<td></td>
</tr>
<tr>
<td>body_mousedownv0.9.2+</td>
<td>Mousedown event of document.body</td>
<td>eevent object</td>
</tr>
<tr>
<td>body_click</td>
<td>Click event of document.body</td>
<td>eevent object</td>
</tr>
</tbody>
</table>
<h3>emit(event, ...args)</h3>
@@ -1219,7 +1256,7 @@ redo. All commands are as follows:</p>
</tr>
<tr>
<td>SET_NODE_DATA</td>
<td>Update node data, that is, update the data in the data object of the node data object</td>
<td>Update node data, that is, update the data in the data object of the node data object. Note that this command will not trigger view updates</td>
<td>node (the node to set), data (object, the data to update, e.g. <code>{expand: true}</code>)</td>
</tr>
<tr>

View File

@@ -48,9 +48,9 @@ a.click()
- `rotateWhenWidthLongerThenHeight`: v0.6.15+, V0.7.0+abandoned, Boolean, false, Automatically rotate 90 degrees when the image has a width to height ratio
- `checkRotate`: v0.7.0+, Function, You can pass a function that takes two parameters, the width and height of the image, and returns true or false. True represents that the image needs to be rotated by 90 degrees
- `checkRotate`: v0.7.0+, (v0.9.2+obsolete), Function, You can pass a function that takes two parameters, the width and height of the image, and returns true or false. True represents that the image needs to be rotated by 90 degrees
- `compress`v0.8.1+null | { width, height }, The parameter for compressing images. In some cases, the length and width of the exported image may be very large. If you want to reduce it, you can use this parameter to control it. Only one width or height can be provided, and it will be scaled proportionally
- `compress`v0.8.1+, (v0.9.2+obsolete)null | { width, height }, The parameter for compressing images. In some cases, the length and width of the exported image may be very large. If you want to reduce it, you can use this parameter to control it. Only one width or height can be provided, and it will be scaled proportionally
Exports as `png`.
@@ -74,15 +74,19 @@ svg(
Exports as `svg`.
### pdf(name, useMultiPageExport, maxImageWidth)
### pdf(name, transparent = false)
> v0.8.1pdf(name, useMultiPageExport, maxImageWidth)
> v0.2.1+
- `name`File name
- `useMultiPageExport`: v0.6.15+, Boolean, false, Whether to export multiple pages, default to single page
- `useMultiPageExport`: v0.6.15+, (v0.9.2+obsolete), Boolean, false, Whether to export multiple pages, default to single page
- `maxImageWidth`v0.8.1+null | NumberThe default is twice the width of A4 paper, which is a parameter for compressing images. In some cases, the length and width of the image may be very large, resulting in a very large PDF volume. Therefore, if you want to reduce the volume, you can use this parameter to control the maximum width of the image
- `maxImageWidth`v0.8.1+, (v0.9.2+obsolete)null | NumberThe default is twice the width of A4 paper, which is a parameter for compressing images. In some cases, the length and width of the image may be very large, resulting in a very large PDF volume. Therefore, if you want to reduce the volume, you can use this parameter to control the maximum width of the image
- `transparent`v0.9.2+Booleandefault is falseSpecify whether the background of the exported image is transparent
Export as `pdf`. Unlike other export methods, this method does not return data and directly triggers the download.

View File

@@ -42,10 +42,10 @@ a.click()
<p><code>rotateWhenWidthLongerThenHeight</code>: v0.6.15+, V0.7.0+abandoned, Boolean, false, Automatically rotate 90 degrees when the image has a width to height ratio</p>
</li>
<li>
<p><code>checkRotate</code>: v0.7.0+, Function, You can pass a function that takes two parameters, the width and height of the image, and returns true or false. True represents that the image needs to be rotated by 90 degrees</p>
<p><code>checkRotate</code>: v0.7.0+, (v0.9.2+obsolete), Function, You can pass a function that takes two parameters, the width and height of the image, and returns true or false. True represents that the image needs to be rotated by 90 degrees</p>
</li>
<li>
<p><code>compress</code>v0.8.1+null | { width, height }, The parameter for compressing images. In some cases, the length and width of the exported image may be very large. If you want to reduce it, you can use this parameter to control it. Only one width or height can be provided, and it will be scaled proportionally</p>
<p><code>compress</code>v0.8.1+, (v0.9.2+obsolete)null | { width, height }, The parameter for compressing images. In some cases, the length and width of the exported image may be very large. If you want to reduce it, you can use this parameter to control it. Only one width or height can be provided, and it will be scaled proportionally</p>
</li>
</ul>
<p>Exports as <code>png</code>.</p>
@@ -69,7 +69,10 @@ a.click()
)
</code></pre>
<p>Exports as <code>svg</code>.</p>
<h3>pdf(name, useMultiPageExport, maxImageWidth)</h3>
<h3>pdf(name, transparent = false)</h3>
<blockquote>
<p>v0.8.1pdf(name, useMultiPageExport, maxImageWidth)</p>
</blockquote>
<blockquote>
<p>v0.2.1+</p>
</blockquote>
@@ -78,10 +81,13 @@ a.click()
<p><code>name</code>File name</p>
</li>
<li>
<p><code>useMultiPageExport</code>: v0.6.15+, Boolean, false, Whether to export multiple pages, default to single page</p>
<p><code>useMultiPageExport</code>: v0.6.15+, (v0.9.2+obsolete), Boolean, false, Whether to export multiple pages, default to single page</p>
</li>
<li>
<p><code>maxImageWidth</code>v0.8.1+null | NumberThe default is twice the width of A4 paper, which is a parameter for compressing images. In some cases, the length and width of the image may be very large, resulting in a very large PDF volume. Therefore, if you want to reduce the volume, you can use this parameter to control the maximum width of the image</p>
<p><code>maxImageWidth</code>v0.8.1+, (v0.9.2+obsolete)null | NumberThe default is twice the width of A4 paper, which is a parameter for compressing images. In some cases, the length and width of the image may be very large, resulting in a very large PDF volume. Therefore, if you want to reduce the volume, you can use this parameter to control the maximum width of the image</p>
</li>
<li>
<p><code>transparent</code>v0.9.2+Booleandefault is falseSpecify whether the background of the exported image is transparent</p>
</li>
</ul>
<p>Export as <code>pdf</code>. Unlike other export methods, this method does not return data and directly triggers the download.</p>

View File

@@ -265,4 +265,8 @@ Open source is not easy. If this project is helpful to you, you can invite the a
<img src="../../../../assets/avatar/HaHN.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>HaHN</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

@@ -221,6 +221,10 @@ full screen, support mini map</li>
<img src="../../../../assets/avatar/HaHN.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>HaHN</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

@@ -217,7 +217,7 @@ if `key` is not passed, return the `data` object
### setData(data)
Set the value of the specified key in the data object of the node's real data
nodeData, `SET_NODE_DATA` command's shortcut method
nodeData, `SET_NODE_DATA` command's shortcut method. This method and command will not update the view, so if you want to modify the text, use the 'setText' method or use the command pointing to the text.
### setText(text, richText)

View File

@@ -161,7 +161,7 @@ default <code>false</code></p>
if <code>key</code> is not passed, return the <code>data</code> object</p>
<h3>setData(data)</h3>
<p>Set the value of the specified key in the data object of the node's real data
nodeData, <code>SET_NODE_DATA</code> command's shortcut method</p>
nodeData, <code>SET_NODE_DATA</code> command's shortcut method. This method and command will not update the view, so if you want to modify the text, use the 'setText' method or use the command pointing to the text.</p>
<h3>setText(text, richText)</h3>
<ul>
<li>

View File

@@ -11,7 +11,13 @@ Gets the current list of active nodes.
### root
Gets the root node of the node tree.
Node tree, also known as the mind map node instance tree.
### renderTree
The rendering tree, also known as the data tree of the mind map.
### layout
## Methods
@@ -114,15 +120,6 @@ Search for the index of a node in the active list.
Get the position index of a node among its siblings.
### removeOneNode(node)
Delete a specific node.
### copyNode()
Copy a node, the active node is the node to be operated on, if there are
multiple active nodes, only the first node will be operated on.
### setNodeDataRender(node, data, notRender)
- `notRender`: v0.6.9+, `Boolean`, Default is `false`, Do not trigger rendering.
@@ -179,16 +176,36 @@ Find the corresponding node instance based on the uid.
> v0.6.8+
Copy nodes. After calling this method, the current activated node data will be stored. Multiple activated nodes will only operate on the first node, and subsequent calls to the 'paste()' method can be pasted.
Copy nodes. After calling this method, the current activated node data will be stored. and subsequent calls to the 'paste()' method can be pasted.
If the browser and protocol (https) support 'js' to manipulate clipboard data, the copied node data will also be added to the user's clipboard.
### cut()
> v0.6.8+
Cut a node. After calling this method, the currently active node will be cut and the node data will be stored. Multiple nodes will only operate on the first node, and subsequent calls to the 'paste()' method can be pasted.
Cut a node. After calling this method, the currently active node will be cut and the node data will be stored. and subsequent calls to the 'paste()' method can be pasted.
If the browser and protocol (https) support 'js' to manipulate clipboard data, the copied node data will also be added to the user's clipboard.
### paste()
> v0.6.8+
Pasting nodes can be done by calling the 'copy()' or 'cut()' method after calling it. This method does not support pasting data from the user's clipboard. Please use the built-in 'Ctrl+v' shortcut key.
Pasting nodes can be done by calling the 'copy()' or 'cut()' method after calling it.
If the browser and protocol (https) support 'js' to manipulate clipboard data, data copied from other places can also be pasted. For example, you can paste' simple mind map 'nodes across browsers. If it is non' simple mind map 'node data, the text and images in the clipboard will be extracted and pasted. The text will be pasted as a child node by default, and the images will be added to the current node by default.
### clearCache()
> v0.9.2+
Empty the node cache pool.
### emitNodeActiveEvent(node = null, activeNodeList = [...this.activeNodeList])
- `node`The node activated this time
- `activeNodeList`All currently activated nodes
Dispatch node activation event, which triggers `node_active` event.

View File

@@ -7,7 +7,10 @@ accessed through <code>mindMap.renderer</code>.</p>
<h3>activeNodeList</h3>
<p>Gets the current list of active nodes.</p>
<h3>root</h3>
<p>Gets the root node of the node tree.</p>
<p>Node tree, also known as the mind map node instance tree.</p>
<h3>renderTree</h3>
<p>The rendering tree, also known as the data tree of the mind map.</p>
<h3>layout</h3>
<h2>Methods</h2>
<h3>highlightNode(node, range)</h3>
<blockquote>
@@ -93,11 +96,6 @@ disable the enter key and delete key related shortcuts to prevent conflicts.</p>
<p>Search for the index of a node in the active list.</p>
<h3>getNodeIndex(node)</h3>
<p>Get the position index of a node among its siblings.</p>
<h3>removeOneNode(node)</h3>
<p>Delete a specific node.</p>
<h3>copyNode()</h3>
<p>Copy a node, the active node is the node to be operated on, if there are
multiple active nodes, only the first node will be operated on.</p>
<h3>setNodeDataRender(node, data, notRender)</h3>
<ul>
<li><code>notRender</code>: v0.6.9+, <code>Boolean</code>, Default is <code>false</code>, Do not trigger rendering.</li>
@@ -151,17 +149,35 @@ is an object, e.g. <code>{text: 'I am new text'}</code>.</p>
<blockquote>
<p>v0.6.8+</p>
</blockquote>
<p>Copy nodes. After calling this method, the current activated node data will be stored. Multiple activated nodes will only operate on the first node, and subsequent calls to the 'paste()' method can be pasted.</p>
<p>Copy nodes. After calling this method, the current activated node data will be stored. and subsequent calls to the 'paste()' method can be pasted.</p>
<p>If the browser and protocol (https) support 'js' to manipulate clipboard data, the copied node data will also be added to the user's clipboard.</p>
<h3>cut()</h3>
<blockquote>
<p>v0.6.8+</p>
</blockquote>
<p>Cut a node. After calling this method, the currently active node will be cut and the node data will be stored. Multiple nodes will only operate on the first node, and subsequent calls to the 'paste()' method can be pasted.</p>
<p>Cut a node. After calling this method, the currently active node will be cut and the node data will be stored. and subsequent calls to the 'paste()' method can be pasted.</p>
<p>If the browser and protocol (https) support 'js' to manipulate clipboard data, the copied node data will also be added to the user's clipboard.</p>
<h3>paste()</h3>
<blockquote>
<p>v0.6.8+</p>
</blockquote>
<p>Pasting nodes can be done by calling the 'copy()' or 'cut()' method after calling it. This method does not support pasting data from the user's clipboard. Please use the built-in 'Ctrl+v' shortcut key.</p>
<p>Pasting nodes can be done by calling the 'copy()' or 'cut()' method after calling it.</p>
<p>If the browser and protocol (https) support 'js' to manipulate clipboard data, data copied from other places can also be pasted. For example, you can paste' simple mind map 'nodes across browsers. If it is non' simple mind map 'node data, the text and images in the clipboard will be extracted and pasted. The text will be pasted as a child node by default, and the images will be added to the current node by default.</p>
<h3>clearCache()</h3>
<blockquote>
<p>v0.9.2+</p>
</blockquote>
<p>Empty the node cache pool.</p>
<h3>emitNodeActiveEvent(node = null, activeNodeList = [...this.activeNodeList])</h3>
<ul>
<li>
<p><code>node</code>The node activated this time</p>
</li>
<li>
<p><code>activeNodeList</code>All currently activated nodes</p>
</li>
</ul>
<p>Dispatch node activation event, which triggers <code>node_active</code> event.</p>
</div>
</template>

View File

@@ -0,0 +1,23 @@
# TextEdit instance
Node text editing instance. It can be obtained through `mindMap.renderer.textEdit`.
## Methods
### isShowTextEdit()
Get whether the current text editing box is in a display state, that is, whether it is in a text editing state.
### hideEditTextBox()
Hiding the text editing box will set the content of the current text editing box as node text.
### registerTmpShortcut()
Register temporary shortcut keys, which means editing can be completed through the Enter and Tab keys.
### show({ node})
- `node`Node instance to enter for editing
Manually enable node editing. By default, it will enter node editing when double clicking or pressing F2 on the node.

View File

@@ -0,0 +1,29 @@
<template>
<div>
<h1>TextEdit instance</h1>
<p>Node text editing instance. It can be obtained through <code>mindMap.renderer.textEdit</code>.</p>
<h2>Methods</h2>
<h3>isShowTextEdit()</h3>
<p>Get whether the current text editing box is in a display state, that is, whether it is in a text editing state.</p>
<h3>hideEditTextBox()</h3>
<p>Hiding the text editing box will set the content of the current text editing box as node text.</p>
<h3>registerTmpShortcut()</h3>
<p>Register temporary shortcut keys, which means editing can be completed through the Enter and Tab keys.</p>
<h3>show({ node})</h3>
<ul>
<li><code>node</code>Node instance to enter for editing</li>
</ul>
<p>Manually enable node editing. By default, it will enter node editing when double clicking or pressing F2 on the node.</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -498,4 +498,8 @@ Check if a cache exists.
#### get(key)
Gets the value of a cache.
Gets the value of a cache.
> v0.9.2+
Empty the cache pool.

View File

@@ -397,6 +397,10 @@ drawBackgroundImageToCanvas(ctx, width, height, img, {
<p>Check if a cache exists.</p>
<h4>get(key)</h4>
<p>Gets the value of a cache.</p>
<blockquote>
<p>v0.9.2+</p>
</blockquote>
<p>Empty the cache pool.</p>
</div>
</template>

View File

@@ -11,6 +11,8 @@ through `mindMap.view`
Zoom the mind map to fit the canvas.
Note that this method cannot be called immediately after calling the 'setData' and 'setFullData' methods, and needs to listen to the 'node_tree_render_end' event calls 'fit'.
### translateX(step)
Translate in the `x` direction, `step`: number of pixels to translate

View File

@@ -9,6 +9,7 @@ through <code>mindMap.view</code></p>
<p>v0.6.0+</p>
</blockquote>
<p>Zoom the mind map to fit the canvas.</p>
<p>Note that this method cannot be called immediately after calling the 'setData' and 'setFullData' methods, and needs to listen to the 'node_tree_render_end' event calls 'fit'.</p>
<h3>translateX(step)</h3>
<p>Translate in the <code>x</code> direction, <code>step</code>: number of pixels to translate</p>
<h3>translateY(step)</h3>

View File

@@ -48,4 +48,10 @@ mindMap.watermark.updateWatermark({
> v0.3.2+
Gets whether the watermark exists.
Gets whether the watermark exists.
### clear()
> v0.9.2+
Clear watermark.

View File

@@ -37,6 +37,11 @@ MindMap.usePlugin(Watermark)
<p>v0.3.2+</p>
</blockquote>
<p>Gets whether the watermark exists.</p>
<h3>clear()</h3>
<blockquote>
<p>v0.9.2+</p>
</blockquote>
<p>Clear watermark.</p>
</div>
</template>

View File

@@ -41,6 +41,7 @@ export default [
{ path: 'miniMap', title: 'MiniMap插件' },
{ path: 'node', title: 'Node实例' },
{ path: 'render', title: 'Render实例' },
{ path: 'textEdit', title: 'TextEdit实例' },
{ path: 'richText', title: 'RichText插件' },
{ path: 'select', title: 'Select 插件 ' },
{ path: 'start', title: '开始' },
@@ -83,6 +84,7 @@ export default [
{ path: 'miniMap', title: 'MiniMap plugin' },
{ path: 'node', title: 'Node instance' },
{ path: 'render', title: 'Render instance' },
{ path: 'textEdit', title: 'TextEdit instance' },
{ path: 'richText', title: 'RichText plugin' },
{ path: 'select', title: 'Select plugin' },
{ path: 'start', title: 'Start' },

View File

@@ -1,5 +1,68 @@
# Changelog
## 0.9.2
修复:
> 1.修复节点文本含有连续的数字或字母时没有换行的问题。
>
> 2.修复导入含有和当前画布已有节点uid相同的文件时会重复绘制节点的问题。
>
> 3.修复当节点数量超出了缓存池的最大数量时,前进回退会导致节点重复渲染的问题。
>
> 4.修复鼠标或触控板水平滚动时画布移动方向相反的问题。
>
> 5.修复节点被销毁时鼠标移入标志没有复位的问题。
>
> 6.修复滚动条插件在initRootNodePosition配置不为默认的[center,center]时位置计算错误的问题。
>
> 7.修复拖拽画布时鼠标在节点上面松开时拖拽无法停止的问题。
>
> 8.修复当画布容器距浏览器窗口左上角不为0时view.fit方法计算出来的位置有误差的问题。
>
> 9.修复当节点数量比较多时,导出的图片中水印没有完全覆盖整个图片的问题。
>
> 10.修复插入公式报错的问题。
>
> 11.修复节点文本编辑状态中鼠标选择文本时移出编辑框,文字选中状态会丢失的问题。
>
> 12.修复节点富文本编辑时文本选中范围为null时没有触发rich_text_selection_change事件的问题。
>
> 13.修复node_dragging事件回参里没有node实例的问题。
>
> 14.修复节点数量过多画布尺寸过大无法导出png的问题。
新增:
> 1.修改mousewheel事件,dir标志修改为dirs,支持存储多个方向,优化触控板的双指移动操作。
>
> 2.TextEdit类增加isShowTextEdit方法判断当前是否处在节点编辑状态。
>
> 3.Render类的paste方法改为支持粘贴剪贴板的数据。
>
> 4.新增将思维导图图形限制在画布内的配置选项。
>
> 5.注册了滚动条插件的情况下,支持配置是否将思维导图限制在画布内。
>
> 6.收起所有节点操作会将思维导图根节点移至画布中心。
>
> 7.支持仅在导出时显示水印的配置选项。
>
> 8.在节点粘贴剪贴板中的图片时,支持自定义处理函数,可以将图片上传到你的服务器。
>
> 9.重构pdf的导出逻辑导出的pdf尺寸不再是固定的a4而是思维导图的尺寸同时删除分页导出的配置。
>
> 10.节点连线支持显示箭头,作为主题的一个字段。
>
> 11.最大历史记录数量默认调整为500。
Demo
> 1.支持配置仅在导出时显示水印。
>
> 2.基础样式配置连线支持显示箭头。
## 0.9.1-fix.2
修复:

View File

@@ -1,6 +1,43 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.9.2</h2>
<p>修复</p>
<blockquote>
<p>1.修复节点文本含有连续的数字或字母时没有换行的问题</p>
<p>2.修复导入含有和当前画布已有节点uid相同的文件时会重复绘制节点的问题</p>
<p>3.修复当节点数量超出了缓存池的最大数量时前进回退会导致节点重复渲染的问题</p>
<p>4.修复鼠标或触控板水平滚动时画布移动方向相反的问题</p>
<p>5.修复节点被销毁时鼠标移入标志没有复位的问题</p>
<p>6.修复滚动条插件在initRootNodePosition配置不为默认的[center,center]时位置计算错误的问题</p>
<p>7.修复拖拽画布时鼠标在节点上面松开时拖拽无法停止的问题</p>
<p>8.修复当画布容器距浏览器窗口左上角不为0时view.fit方法计算出来的位置有误差的问题</p>
<p>9.修复当节点数量比较多时导出的图片中水印没有完全覆盖整个图片的问题</p>
<p>10.修复插入公式报错的问题</p>
<p>11.修复节点文本编辑状态中鼠标选择文本时移出编辑框文字选中状态会丢失的问题</p>
<p>12.修复节点富文本编辑时文本选中范围为null时没有触发rich_text_selection_change事件的问题</p>
<p>13.修复node_dragging事件回参里没有node实例的问题</p>
<p>14.修复节点数量过多画布尺寸过大无法导出png的问题</p>
</blockquote>
<p>新增</p>
<blockquote>
<p>1.修改mousewheel事件,dir标志修改为dirs,支持存储多个方向,优化触控板的双指移动操作</p>
<p>2.TextEdit类增加isShowTextEdit方法判断当前是否处在节点编辑状态</p>
<p>3.Render类的paste方法改为支持粘贴剪贴板的数据</p>
<p>4.新增将思维导图图形限制在画布内的配置选项</p>
<p>5.注册了滚动条插件的情况下支持配置是否将思维导图限制在画布内</p>
<p>6.收起所有节点操作会将思维导图根节点移至画布中心</p>
<p>7.支持仅在导出时显示水印的配置选项</p>
<p>8.在节点粘贴剪贴板中的图片时支持自定义处理函数可以将图片上传到你的服务器</p>
<p>9.重构pdf的导出逻辑导出的pdf尺寸不再是固定的a4而是思维导图的尺寸同时删除分页导出的配置</p>
<p>10.节点连线支持显示箭头作为主题的一个字段</p>
<p>11.最大历史记录数量默认调整为500</p>
</blockquote>
<p>Demo</p>
<blockquote>
<p>1.支持配置仅在导出时显示水印</p>
<p>2.基础样式配置连线支持显示箭头</p>
</blockquote>
<h2>0.9.1-fix.2</h2>
<p>修复</p>
<blockquote>

View File

@@ -61,7 +61,7 @@ const mindMap = new MindMap({
| nodeTextEditZIndexv0.5.5+ | Number | 3000 | 节点文本编辑框元素的z-index |
| nodeNoteTooltipZIndexv0.5.5+ | Number | 3000 | 节点备注浮层元素的z-index |
| isEndNodeTextEditOnClickOuterv0.5.5+ | Boolean | true | 是否在点击了画布外的区域时结束节点文本的编辑状态 |
| maxHistoryCountv0.5.6+ | Number | 1000 | 最大历史记录数 |
| maxHistoryCountv0.5.6+ | Number | 1000v0.9.2+改为500 | 最大历史记录数 |
| alwaysShowExpandBtnv0.5.8+ | Boolean | false | 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示 |
| iconListv0.5.8+ | Array | [] | 扩展节点可插入的图标,数组的每一项为一个对象,对象详细结构请参考下方【图标配置】表格 |
| maxNodeCacheCountv0.5.10+ | Number | 1000 | 节点最大缓存数量。为了优化性能,内部会维护一个节点缓存池,用来复用节点,通过该属性可以指定池的最大缓存数量 |
@@ -105,6 +105,9 @@ const mindMap = new MindMap({
| 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配置不再起作用 |
### 数据结构
@@ -156,6 +159,7 @@ const mindMap = new MindMap({
| textSpacing | Number | 100 | 同一行水印之间的间距 |
| angle | Number | 30 | 水印的倾斜角度,范围:[0, 90] |
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | 水印文字样式 |
| onlyExportv0.9.2+ | Boolean | false | 是否仅在导出时添加水印 |
### 图标配置
@@ -379,7 +383,7 @@ mindMap.setTheme('主题名称')
| mousemove | el元素的鼠标移动事件 | e事件对象、thisEvent事件类实例 |
| drag | 如果是按住左键拖动的话会触发拖动事件 | e事件对象、thisEvent事件类实例 |
| mouseup | el元素的鼠标松开事件 | e事件对象、thisEvent事件类实例 |
| mousewheel | 鼠标滚动事件 | e事件对象、dir向上up还是向下down滚动、thisEvent事件类实例、isTouchPadv0.6.1+,是否是触控板触发的事件) |
| mousewheel | 鼠标滚动事件 | e事件对象、dir向上up还是向下down滚动。v0.9.2+已改为dirs数组类型即支持同时保存多个方向、thisEvent事件类实例、isTouchPadv0.6.1+,是否是触控板触发的事件) |
| contextmenu | svg画布的鼠标右键菜单事件 | e事件对象 |
| node_click | 节点的单击事件 | this节点实例、e事件对象 |
| node_mousedown | 节点的鼠标按下事件 | this节点实例、e事件对象 |
@@ -411,6 +415,8 @@ mindMap.setTheme('主题名称')
| set_datav0.7.3+ | 调用了setData方法动态设置思维导图数据时触发 | data新的思维导图数据 |
| resizev0.8.0+ | 容器尺寸改变后触发,实际上是当思维导图实例的`resize`方法被调用后触发 | |
| beforeDestroyv0.9.0+ | 思维导图销毁前触发即调用了destroy方法触发 | |
| body_mousedownv0.9.2+ | document.body的鼠标按下事件 | e事件对象 |
| body_click | document.body的点击事件 | e事件对象 |
### emit(event, ...args)
@@ -502,7 +508,7 @@ mindMap.updateConfig({
| EXPAND_ALL | 展开所有节点 | |
| UNEXPAND_ALL | 收起所有节点 | |
| UNEXPAND_TO_LEVELv0.2.8+ | 展开到指定层级 | level要展开到的层级1、2、3... |
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据 | node要设置的节点、data对象要更新的数据`{expand: true}` |
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据,注意这个命令不会触发视图的更新 | node要设置的节点、data对象要更新的数据`{expand: true}` |
| SET_NODE_TEXT | 设置节点文本 | node要设置的节点、text要设置的文本字符串换行可以使用`\n`、richTextv0.4.0+,如果要设置的是富文本字符,需要设为`true`、resetRichTextv0.6.10+是否要复位富文本默认为false如果传true那么会重置富文本节点的样式 |
| SET_NODE_IMAGE | 设置节点图片 | node要设置的节点、imgData对象图片信息结构为`{url, title, width, height}`,图片的宽高必须要传) |
| SET_NODE_ICON | 设置节点图标 | node要设置的节点、icons数组预定义的图片名称组成的数组可用图标可在[icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件里的`nodeIconList`列表里获取到,图标名称为`type_name`,如`['priority_1']` |

View File

@@ -252,7 +252,7 @@
<tr>
<td>maxHistoryCountv0.5.6+</td>
<td>Number</td>
<td>1000</td>
<td>1000v0.9.2+改为500</td>
<td>最大历史记录数</td>
</tr>
<tr>
@@ -513,6 +513,24 @@
<td></td>
<td>图片地址当节点图片加载失败时显示的默认图片</td>
</tr>
<tr>
<td>handleNodePasteImgv0.9.2+</td>
<td>null Function</td>
<td>null</td>
<td>在节点上粘贴剪贴板中的图片的处理方法默认是转换为data:url数据插入到节点中你可以通过该方法来将图片数据上传到服务器实现保存图片的url可以传递一个异步方法接收Blob类型的图片数据需要返回指定结构{ url, size: {width, height} }</td>
</tr>
<tr>
<td>isLimitMindMapInCanvasv0.9.2+</td>
<td>Boolean</td>
<td>false</td>
<td>是否将思维导图限制在画布内比如向右拖动时思维导图图形的最左侧到达画布中心时将无法继续向右拖动其他同理</td>
</tr>
<tr>
<td>isLimitMindMapInCanvasWhenHasScrollbarv0.9.2+</td>
<td>Boolean</td>
<td>true</td>
<td>当注册了滚动条插件Scrollbar是否将思维导图限制在画布内isLimitMindMapInCanvas配置不再起作用</td>
</tr>
</tbody>
</table>
<h3>数据结构</h3>
@@ -592,6 +610,12 @@
<td>{color: '#999', opacity: 0.5, fontSize: 14}</td>
<td>水印文字样式</td>
</tr>
<tr>
<td>onlyExportv0.9.2+</td>
<td>Boolean</td>
<td>false</td>
<td>是否仅在导出时添加水印</td>
</tr>
</tbody>
</table>
<h3>图标配置</h3>
@@ -826,7 +850,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>mousewheel</td>
<td>鼠标滚动事件</td>
<td>e事件对象dir向上up还是向下down滚动thisEvent事件类实例isTouchPadv0.6.1+是否是触控板触发的事件</td>
<td>e事件对象dir向上up还是向下down滚动v0.9.2+已改为dirs数组类型即支持同时保存多个方向thisEvent事件类实例isTouchPadv0.6.1+是否是触控板触发的事件</td>
</tr>
<tr>
<td>contextmenu</td>
@@ -983,6 +1007,16 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<td>思维导图销毁前触发即调用了destroy方法触发</td>
<td></td>
</tr>
<tr>
<td>body_mousedownv0.9.2+</td>
<td>document.body的鼠标按下事件</td>
<td>e事件对象</td>
</tr>
<tr>
<td>body_click</td>
<td>document.body的点击事件</td>
<td>e事件对象</td>
</tr>
</tbody>
</table>
<h3>emit(event, ...args)</h3>
@@ -1132,7 +1166,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
</tr>
<tr>
<td>SET_NODE_DATA</td>
<td>更新节点数据即更新节点数据对象里<code>data</code>对象的数据</td>
<td>更新节点数据即更新节点数据对象里<code>data</code>对象的数据注意这个命令不会触发视图的更新</td>
<td>node要设置的节点data对象要更新的数据<code>{expand: true}</code></td>
</tr>
<tr>

View File

@@ -1,6 +1,6 @@
# 结构
`simple-mind-map`目前支持四种结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图、timeline时间轴、timeline2时间轴2、fishbone鱼骨图、verticalTimelinev0.6.6+竖向时间轴)。
`simple-mind-map`目前支持结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图、timeline时间轴、timeline2时间轴2、fishbone鱼骨图、verticalTimelinev0.6.6+竖向时间轴)。
可以在实例化`simple-mind-map`时通过选项指定使用的结构:

View File

@@ -1,7 +1,7 @@
<template>
<div>
<h1>结构</h1>
<p><code>simple-mind-map</code>目前支持四种结构logicalStructure逻辑结构图mindMap思维导图organizationStructure组织结构图catalogOrganization目录组织图timeline时间轴timeline2时间轴2fishbone鱼骨图verticalTimelinev0.6.6+竖向时间轴</p>
<p><code>simple-mind-map</code>目前支持结构logicalStructure逻辑结构图mindMap思维导图organizationStructure组织结构图catalogOrganization目录组织图timeline时间轴timeline2时间轴2fishbone鱼骨图verticalTimelinev0.6.6+竖向时间轴</p>
<p>可以在实例化<code>simple-mind-map</code>时通过选项指定使用的结构</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-comment">// ...</span>

View File

@@ -15,6 +15,10 @@
name: '插入同级节点',
value: 'Enter'
},
{
name: '插入父节点',
value: 'Shift + Tab'
},
{
name: '上移节点',
value: 'Ctrl + ↑'
@@ -35,6 +39,10 @@
name: '删除节点',
value: 'Delete | Backspace'
},
{
name: '仅删除当前节点',
value: 'Shift + Backspace'
},
{
name: '复制节点',
value: 'Ctrl + C'
@@ -89,8 +97,16 @@
value: 'Ctrl + -'
},
{
name: '恢复默认',
name: '放大缩小',
value: 'Ctrl + 鼠标滚动'
},
{
name: '回到根节点',
value: 'Ctrl + Enter'
},
{
name: '适应画布',
value: 'Ctrl + i'
}
]
}

Some files were not shown because too many files have changed in this diff Show More