Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc1cf71eaa | ||
|
|
d929792157 | ||
|
|
658b47b72e | ||
|
|
591e6a5b2a | ||
|
|
58baf4c0aa | ||
|
|
00f86fe167 | ||
|
|
5c1e5f072c | ||
|
|
b45674cf8f | ||
|
|
c23a16e65a | ||
|
|
b7722987b1 | ||
|
|
1fc5b951a0 | ||
|
|
53eb608007 | ||
|
|
876afb2504 | ||
|
|
4d1608e8c4 | ||
|
|
80f45e5e7d | ||
|
|
f80317a449 | ||
|
|
9bce6d3ded | ||
|
|
16e40b4342 | ||
|
|
624203ea84 | ||
|
|
6ffa4570d4 | ||
|
|
d99a4dcc33 | ||
|
|
e8c4aad690 | ||
|
|
35c8e129f0 | ||
|
|
dc096fd535 | ||
|
|
a047dabbd0 | ||
|
|
1ec723db0e | ||
|
|
d9fc209dac | ||
|
|
8647cb5893 |
18
README.md
@@ -28,7 +28,7 @@ Github:[releases](https://github.com/wanglin2/mind-map/releases)。百度云
|
||||
# 特性
|
||||
|
||||
- [x] 插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积
|
||||
- [x] 支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构
|
||||
- [x] 支持逻辑结构图(向左、向右逻辑结构图)、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构
|
||||
- [x] 内置多种主题,允许高度自定义样式,支持注册新主题
|
||||
- [x] 节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式
|
||||
- [x] 节点支持拖拽(拖拽移动、自由调整)、多种节点形状;支持扩展节点内容、支持使用 DDM 完全自定义节点内容
|
||||
@@ -42,7 +42,7 @@ Github:[releases](https://github.com/wanglin2/mind-map/releases)。百度云
|
||||
|
||||
官方提供了如下插件,可根据需求按需引入(某个功能不生效大概率是因为你没有引入对应的插件),具体使用方式请查看文档:
|
||||
|
||||
> RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]
|
||||
> RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、OuterFrame(外框插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]
|
||||
|
||||
本项目不会实现的特性:
|
||||
|
||||
@@ -111,7 +111,7 @@ const mindMap = new MindMap({
|
||||
|
||||
# 关于定制
|
||||
|
||||
如果你有个性化的商用定制需求,可以联系我们,我们提供付费开发服务。
|
||||
如果你有个性化的商用定制需求,可以联系我们,我们提供付费开发服务,无论前端、后端、还是部署,都可以帮你一站式搞定。
|
||||
|
||||
# 请作者喝杯咖啡
|
||||
|
||||
@@ -401,4 +401,16 @@ const mindMap = new MindMap({
|
||||
<img src="./web/src/assets/avatar/Kyle.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>Kyle</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/lsytyrt.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>lsytyrt</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/秀树因馨雨.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>秀树因馨雨</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/buddy.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>buddy</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
2
dist/css/app.css
vendored
BIN
dist/fonts/iconfont.ttf
vendored
BIN
dist/fonts/iconfont.woff
vendored
BIN
dist/fonts/iconfont.woff2
vendored
BIN
dist/img/buddy.jpg
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
dist/img/logicalStructureLeft.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
dist/img/秀树因馨雨.jpg
vendored
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
dist/img/错误.jpg
vendored
Normal file
|
After Width: | Height: | Size: 60 KiB |
2
dist/js/app.js
vendored
2
dist/js/chunk-2d0a3179.js
vendored
2
dist/js/chunk-2d0ab10b.js
vendored
2
dist/js/chunk-2d0abe0f.js
vendored
@@ -1 +1 @@
|
||||
(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}}]);
|
||||
(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("scale")]),e._v(": Scaling values, not scaled to '1', scaled to '1' for values less than, scaled to '1' for values greater than, scaled to '1' for values greater than")])]),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={},c=v,s=o("2877"),i=Object(s["a"])(c,a,n,!1,null,null,null);t["default"]=i.exports}}]);
|
||||
1
dist/js/chunk-2d0ae956.js
vendored
Normal file
2
dist/js/chunk-2d0c191e.js
vendored
2
dist/js/chunk-2d0d9fbc.js
vendored
2
dist/js/chunk-2d0dad5f.js
vendored
2
dist/js/chunk-2d0db0f2.js
vendored
@@ -1 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0db0f2"],{"6df4":function(v,_,e){"use strict";e.r(_);var n=function(){var v=this;v._self._c;return v._m(0)},o=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("Command 实例")]),_("p",[_("code",[v._v("command")]),v._v("实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过"),_("code",[v._v("mindMap.command")]),v._v("获取到该实例")]),_("h2",[v._v("方法")]),_("h3",[v._v("pause()")]),_("blockquote",[_("p",[v._v("v0.9.11+")])]),_("p",[v._v("暂停收集历史数据。")]),_("h3",[v._v("recovery()")]),_("blockquote",[_("p",[v._v("v0.9.11+")])]),_("p",[v._v("恢复收集历史数据。")]),_("h3",[v._v("add(name, fn)")]),_("p",[v._v("添加命令。")]),_("p",[_("code",[v._v("name")]),v._v(":命令名称")]),_("p",[_("code",[v._v("fn")]),v._v(":命令要执行的方法")]),_("h3",[v._v("remove(name, fn)")]),_("p",[v._v("移除命令。")]),_("p",[_("code",[v._v("name")]),v._v(":要移除的命令名称")]),_("p",[_("code",[v._v("fn")]),v._v(":要移除的方法,不传的话移除该命令所有的方法")]),_("h3",[v._v("getCopyData()")]),_("p",[v._v("获取渲染树数据副本")]),_("h3",[v._v("clearHistory()")]),_("p",[v._v("清空历史堆栈数据")])])}],c={},p=c,a=e("2877"),d=Object(a["a"])(p,n,o,!1,null,null,null);_["default"]=d.exports}}]);
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0db0f2"],{"6df4":function(v,_,e){"use strict";e.r(_);var n=function(){var v=this;v._self._c;return v._m(0)},o=[function(){var v=this,_=v._self._c;return _("div",[_("h1",[v._v("Command 实例")]),_("p",[_("code",[v._v("command")]),v._v("实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过"),_("code",[v._v("mindMap.command")]),v._v("获取到该实例")]),_("h2",[v._v("属性")]),_("h3",[v._v("history")]),_("p",[v._v("当前所有的历史数据列表。不要手动修改该数组。")]),_("h3",[v._v("activeHistoryIndex")]),_("p",[v._v("当前所在的历史数据索引。不要手动修改该属性。")]),_("h2",[v._v("方法")]),_("p",[v._v("前进后退请使用命令"),_("code",[v._v("BACK")]),v._v("或"),_("code",[v._v("FORWARD")]),v._v("。")]),_("h3",[v._v("pause()")]),_("blockquote",[_("p",[v._v("v0.9.11+")])]),_("p",[v._v("暂停收集历史数据。")]),_("h3",[v._v("recovery()")]),_("blockquote",[_("p",[v._v("v0.9.11+")])]),_("p",[v._v("恢复收集历史数据。")]),_("h3",[v._v("add(name, fn)")]),_("p",[v._v("添加命令。")]),_("p",[_("code",[v._v("name")]),v._v(":命令名称")]),_("p",[_("code",[v._v("fn")]),v._v(":命令要执行的方法")]),_("h3",[v._v("remove(name, fn)")]),_("p",[v._v("移除命令。")]),_("p",[_("code",[v._v("name")]),v._v(":要移除的命令名称")]),_("p",[_("code",[v._v("fn")]),v._v(":要移除的方法,不传的话移除该命令所有的方法")]),_("h3",[v._v("getCopyData()")]),_("p",[v._v("获取渲染树数据副本。即当前画布的数据。")]),_("h3",[v._v("clearHistory()")]),_("p",[v._v("清空历史堆栈数据")])])}],c={},p=c,d=e("2877"),a=Object(d["a"])(p,n,o,!1,null,null,null);_["default"]=a.exports}}]);
|
||||
2
dist/js/chunk-2d0dddce.js
vendored
@@ -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)},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}}]);
|
||||
(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("缩放思维导图至适应画布。")]),_("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("scale")]),v._v(": 缩放数值,未缩放为"),_("code",[v._v("1")]),v._v(",小于为"),_("code",[v._v("1")]),v._v("缩小,大于"),_("code",[v._v("1")]),v._v("为放大")])]),_("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={},a=t,p=e("2877"),d=Object(p["a"])(a,c,o,!1,null,null,null);_["default"]=d.exports}}]);
|
||||
2
dist/js/chunk-2d0e5089.js
vendored
@@ -1 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0e5089"],{9381:function(e,o,a){"use strict";a.r(o);var n=function(){var e=this;e._self._c;return e._m(0)},t=[function(){var e=this,o=e._self._c;return o("div",[o("h1",[e._v("command instance")]),o("p",[e._v("The "),o("code",[e._v("command")]),e._v(" instance is responsible for adding and executing commands. It includes many built-in commands and can also be added manually. A command refers to an operation that needs to add a copy to the history stack data. The "),o("code",[e._v("mindMap.command")]),e._v(' instance can be obtained through this."')]),o("h2",[e._v("Methods")]),o("h3",[e._v("pause()")]),o("blockquote",[o("p",[e._v("v0.9.11+")])]),o("p",[e._v("Pause collecting historical data.")]),o("h3",[e._v("recovery()")]),o("blockquote",[o("p",[e._v("v0.9.11+")])]),o("p",[e._v("Restore the collection of historical data.")]),o("h3",[e._v("add(name, fn)")]),o("p",[e._v("Add a command.")]),o("p",[o("code",[e._v("name")]),e._v(": Command name")]),o("p",[o("code",[e._v("fn")]),e._v(": Method to be executed by the command")]),o("h3",[e._v("remove(name, fn)")]),o("p",[e._v("Remove a command.")]),o("p",[o("code",[e._v("name")]),e._v(": Name of the command to be removed")]),o("p",[o("code",[e._v("fn")]),e._v(": Method to be removed, if not provided all methods for the command will be removed")]),o("h3",[e._v("getCopyData()")]),o("p",[e._v("Get a copy of the rendering tree data")]),o("h3",[e._v("clearHistory()")]),o("p",[e._v("Clear the history stack data")])])}],d={},c=d,v=a("2877"),m=Object(v["a"])(c,n,t,!1,null,null,null);o["default"]=m.exports}}]);
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0e5089"],{9381:function(e,a,o){"use strict";o.r(a);var t=function(){var e=this;e._self._c;return e._m(0)},n=[function(){var e=this,a=e._self._c;return a("div",[a("h1",[e._v("command instance")]),a("p",[e._v("The "),a("code",[e._v("command")]),e._v(" instance is responsible for adding and executing commands. It includes many built-in commands and can also be added manually. A command refers to an operation that needs to add a copy to the history stack data. The "),a("code",[e._v("mindMap.command")]),e._v(' instance can be obtained through this."')]),a("h2",[e._v("Props")]),a("h3",[e._v("history")]),a("p",[e._v("The current list of all historical data. Do not manually modify the array.")]),a("h3",[e._v("activeHistoryIndex")]),a("p",[e._v("The current historical data index. Do not manually modify this property.")]),a("h2",[e._v("Methods")]),a("p",[e._v("Please use the command 'Back' or 'FORWARD' to move forward or backward.")]),a("h3",[e._v("pause()")]),a("blockquote",[a("p",[e._v("v0.9.11+")])]),a("p",[e._v("Pause collecting historical data.")]),a("h3",[e._v("recovery()")]),a("blockquote",[a("p",[e._v("v0.9.11+")])]),a("p",[e._v("Restore the collection of historical data.")]),a("h3",[e._v("add(name, fn)")]),a("p",[e._v("Add a command.")]),a("p",[a("code",[e._v("name")]),e._v(": Command name")]),a("p",[a("code",[e._v("fn")]),e._v(": Method to be executed by the command")]),a("h3",[e._v("remove(name, fn)")]),a("p",[e._v("Remove a command.")]),a("p",[a("code",[e._v("name")]),e._v(": Name of the command to be removed")]),a("p",[a("code",[e._v("fn")]),e._v(": Method to be removed, if not provided all methods for the command will be removed")]),a("h3",[e._v("getCopyData()")]),a("p",[e._v("Get a copy of the rendering tree data. That is, the data of the current canvas.")]),a("h3",[e._v("clearHistory()")]),a("p",[e._v("Clear the history stack data")])])}],d={},c=d,r=o("2877"),v=Object(r["a"])(c,t,n,!1,null,null,null);a["default"]=v.exports}}]);
|
||||
2
dist/js/chunk-2d0f026c.js
vendored
2
dist/js/chunk-2d208ffa.js
vendored
2
dist/js/chunk-2d20f68f.js
vendored
2
dist/js/chunk-2d210a7a.js
vendored
1
dist/js/chunk-2d21e7f1.js
vendored
Normal file
2
dist/js/chunk-2d2254a4.js
vendored
1
dist/js/chunk-428b560e.js
vendored
Normal file
1
dist/js/chunk-6fd88c2d.js
vendored
Normal file
1
dist/js/chunk-835a4a40.js
vendored
1
dist/js/chunk-ba08bba8.js
vendored
@@ -5,7 +5,7 @@
|
||||
id: 'KRO0WxK8GT66tYCQ',
|
||||
ck: 'KRO0WxK8GT66tYCQ',
|
||||
autoTrack: false
|
||||
})</script><link href="dist/css/chunk-vendors.css?06beb05ed1be887c6e20" rel="stylesheet"><link href="dist/css/app.css?06beb05ed1be887c6e20" 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 = () => {
|
||||
})</script><link href="dist/css/chunk-vendors.css?dd8fa3cd99060d550179" rel="stylesheet"><link href="dist/css/app.css?dd8fa3cd99060d550179" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
@@ -70,4 +70,4 @@
|
||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||
// 实例化页面
|
||||
window.initApp()
|
||||
}</script><script src="dist/js/chunk-vendors.js?06beb05ed1be887c6e20"></script><script src="dist/js/app.js?06beb05ed1be887c6e20"></script></body></html>
|
||||
}</script><script src="dist/js/chunk-vendors.js?dd8fa3cd99060d550179"></script><script src="dist/js/app.js?dd8fa3cd99060d550179"></script></body></html>
|
||||
@@ -17,6 +17,7 @@ import Scrollbar from './src/plugins/Scrollbar.js'
|
||||
import Formula from './src/plugins/Formula.js'
|
||||
import RainbowLines from './src/plugins/RainbowLines.js'
|
||||
import Demonstrate from './src/plugins/Demonstrate.js'
|
||||
import OuterFrame from './src/plugins/OuterFrame.js'
|
||||
import xmind from './src/parse/xmind.js'
|
||||
import markdown from './src/parse/markdown.js'
|
||||
import icons from './src/svg/icons.js'
|
||||
@@ -30,7 +31,7 @@ MindMap.iconList = icons.nodeIconList
|
||||
MindMap.constants = constants
|
||||
MindMap.themes = themes
|
||||
MindMap.defaultTheme = defaultTheme
|
||||
MindMap.version = '0.10.1'
|
||||
MindMap.version = '0.10.2'
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
@@ -50,5 +51,6 @@ MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Formula)
|
||||
.usePlugin(RainbowLines)
|
||||
.usePlugin(Demonstrate)
|
||||
.usePlugin(OuterFrame)
|
||||
|
||||
export default MindMap
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.10.1",
|
||||
"version": "0.10.2",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -174,6 +174,7 @@ export const CONSTANTS = {
|
||||
},
|
||||
LAYOUT: {
|
||||
LOGICAL_STRUCTURE: 'logicalStructure',
|
||||
LOGICAL_STRUCTURE_LEFT: 'logicalStructureLeft',
|
||||
MIND_MAP: 'mindMap',
|
||||
ORGANIZATION_STRUCTURE: 'organizationStructure',
|
||||
CATALOG_ORGANIZATION: 'catalogOrganization',
|
||||
@@ -251,6 +252,10 @@ export const layoutList = [
|
||||
name: '逻辑结构图',
|
||||
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE
|
||||
},
|
||||
{
|
||||
name: '向左逻辑结构图',
|
||||
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT
|
||||
},
|
||||
{
|
||||
name: '思维导图',
|
||||
value: CONSTANTS.LAYOUT.MIND_MAP
|
||||
@@ -282,6 +287,7 @@ export const layoutList = [
|
||||
]
|
||||
export const layoutValueList = [
|
||||
CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
|
||||
CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT,
|
||||
CONSTANTS.LAYOUT.MIND_MAP,
|
||||
CONSTANTS.LAYOUT.CATALOG_ORGANIZATION,
|
||||
CONSTANTS.LAYOUT.ORGANIZATION_STRUCTURE,
|
||||
@@ -315,7 +321,8 @@ export const nodeDataNoStylePropList = [
|
||||
'associativeLineText',
|
||||
'attachmentUrl',
|
||||
'attachmentName',
|
||||
'notation'
|
||||
'notation',
|
||||
'outerFrame'
|
||||
]
|
||||
|
||||
// 错误类型
|
||||
|
||||
@@ -221,6 +221,11 @@ export const defaultOpt = {
|
||||
createNodePrefixContent: null,
|
||||
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
|
||||
createNodePostfixContent: null,
|
||||
// 禁止粘贴用户剪贴板中的数据,禁止将复制的数据写入用户的剪贴板中
|
||||
disabledClipboard: false,
|
||||
// 自定义超链接的跳转
|
||||
// 如果不传,默认会以新窗口的方式打开超链接,可以传递一个函数,函数接收两个参数:link(超链接的url)、node(所属节点实例),只要传递了函数,就会阻止默认的跳转
|
||||
customHyperlinkJump: null,
|
||||
|
||||
// 【Select插件】
|
||||
// 多选节点时鼠标移动到边缘时的画布移动偏移量
|
||||
@@ -256,6 +261,8 @@ export const defaultOpt = {
|
||||
handleDragCloneNode: null,
|
||||
// 即将拖拽完成前调用该函数,函数接收一个对象作为参数:{overlapNodeUid,prevNodeUid,nextNodeUid},代表拖拽信息,如果要阻止本次拖拽,那么可以返回true,此时node_dragend事件不会再触发。函数可以是异步函数,返回Promise实例
|
||||
beforeDragEnd: null,
|
||||
// 即将开始调整节点前调用该函数,函数接收当前即将被拖拽的节点实例列表作为参数,如果要阻止本次拖拽,那么可以返回true
|
||||
beforeDragStart: null,
|
||||
|
||||
// 【Watermark插件】
|
||||
// 水印配置
|
||||
@@ -380,5 +387,5 @@ export const defaultOpt = {
|
||||
beforeHideRichTextEdit: null,
|
||||
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
|
||||
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果
|
||||
richTextEditFakeInPlace: false,
|
||||
richTextEditFakeInPlace: false
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ class Event extends EventEmitter {
|
||||
|
||||
// 鼠标按下事件
|
||||
onMousedown(e) {
|
||||
e.preventDefault()
|
||||
// 鼠标左键
|
||||
if (e.which === 1) {
|
||||
this.isLeftMousedown = true
|
||||
@@ -114,6 +115,7 @@ class Event extends EventEmitter {
|
||||
|
||||
// 鼠标移动事件
|
||||
onMousemove(e) {
|
||||
e.preventDefault()
|
||||
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
|
||||
this.mousemovePos.x = e.clientX
|
||||
this.mousemovePos.y = e.clientY
|
||||
|
||||
@@ -42,6 +42,8 @@ import { Polygon } from '@svgdotjs/svg.js'
|
||||
const layouts = {
|
||||
// 逻辑结构图
|
||||
[CONSTANTS.LAYOUT.LOGICAL_STRUCTURE]: LogicalStructure,
|
||||
// 向左逻辑结构图
|
||||
[CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT]: LogicalStructure,
|
||||
// 思维导图
|
||||
[CONSTANTS.LAYOUT.MIND_MAP]: MindMap,
|
||||
// 目录组织图
|
||||
@@ -1013,14 +1015,18 @@ class Render {
|
||||
copy() {
|
||||
this.beingCopyData = this.copyNode()
|
||||
if (!this.beingCopyData) return
|
||||
setDataToClipboard(createSmmFormatData(this.beingCopyData))
|
||||
if (!this.mindMap.opt.disabledClipboard) {
|
||||
setDataToClipboard(createSmmFormatData(this.beingCopyData))
|
||||
}
|
||||
}
|
||||
|
||||
// 剪切节点
|
||||
cut() {
|
||||
this.mindMap.execCommand('CUT_NODE', copyData => {
|
||||
this.beingCopyData = copyData
|
||||
setDataToClipboard(createSmmFormatData(copyData))
|
||||
if (!this.mindMap.opt.disabledClipboard) {
|
||||
setDataToClipboard(createSmmFormatData(copyData))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1029,17 +1035,20 @@ class Render {
|
||||
const {
|
||||
errorHandler,
|
||||
handleIsSplitByWrapOnPasteCreateNewNode,
|
||||
handleNodePasteImg
|
||||
handleNodePasteImg,
|
||||
disabledClipboard
|
||||
} = this.mindMap.opt
|
||||
// 读取剪贴板的文字和图片
|
||||
let text = null
|
||||
let text = ''
|
||||
let img = null
|
||||
try {
|
||||
const res = await getDataFromClipboard()
|
||||
text = res.text
|
||||
img = res.img
|
||||
} catch (error) {
|
||||
errorHandler(ERROR_TYPES.READ_CLIPBOARD_ERROR, error)
|
||||
if (!disabledClipboard) {
|
||||
try {
|
||||
const res = await getDataFromClipboard()
|
||||
text = res.text || ''
|
||||
img = res.img || null
|
||||
} catch (error) {
|
||||
errorHandler(ERROR_TYPES.READ_CLIPBOARD_ERROR, error)
|
||||
}
|
||||
}
|
||||
// 检查剪切板数据是否有变化
|
||||
// 通过图片大小来判断图片是否发生变化,可能是不准确的,但是目前没有其他好方法
|
||||
|
||||
@@ -286,7 +286,6 @@ export default class TextEdit {
|
||||
|
||||
// 隐藏文本编辑框
|
||||
hideEditTextBox() {
|
||||
this.currentNode = null
|
||||
if (this.mindMap.richText) {
|
||||
return this.mindMap.richText.hideEditText()
|
||||
}
|
||||
@@ -305,8 +304,10 @@ export default class TextEdit {
|
||||
this.mindMap.emit(
|
||||
'hide_text_edit',
|
||||
this.textEditNode,
|
||||
this.renderer.activeNodeList
|
||||
this.renderer.activeNodeList,
|
||||
this.currentNode
|
||||
)
|
||||
this.currentNode = null
|
||||
this.textEditNode.style.display = 'none'
|
||||
this.textEditNode.innerHTML = ''
|
||||
this.textEditNode.style.fontFamily = 'inherit'
|
||||
|
||||
@@ -427,7 +427,7 @@ class Node {
|
||||
;(this._textData.nodeContent || this._textData.node)
|
||||
.x(-oldX) // 修复非富文本模式下同时存在图标和换行的文本时,被收起和展开时图标与文字距离会逐渐拉大的问题
|
||||
.x(textContentOffsetX)
|
||||
.y(0)
|
||||
.y((this._rectInfo.textContentHeight - this._textData.height) / 2)
|
||||
textContentNested.add(this._textData.node)
|
||||
textContentOffsetX += this._textData.width + textContentItemMargin
|
||||
}
|
||||
@@ -515,6 +515,7 @@ class Node {
|
||||
this.active(e)
|
||||
})
|
||||
this.group.on('mousedown', e => {
|
||||
e.preventDefault()
|
||||
const {
|
||||
readonly,
|
||||
enableCtrlKeyNodeSelection,
|
||||
|
||||
@@ -254,12 +254,16 @@ function createHyperlinkNode() {
|
||||
if (!hyperlink) {
|
||||
return
|
||||
}
|
||||
const { customHyperlinkJump } = this.mindMap.opt
|
||||
let iconSize = this.mindMap.themeConfig.iconSize
|
||||
let node = new SVG().size(iconSize, iconSize)
|
||||
// 超链接节点
|
||||
let a = new A().to(hyperlink).target('_blank')
|
||||
a.node.addEventListener('click', e => {
|
||||
e.stopPropagation()
|
||||
if (typeof customHyperlinkJump === 'function') {
|
||||
e.preventDefault()
|
||||
customHyperlinkJump(hyperlink, this)
|
||||
}
|
||||
})
|
||||
if (hyperlinkTitle) {
|
||||
node.add(SVG(`<title>${hyperlinkTitle}</title>`))
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun, getNodeIndexInNodeList } from '../utils'
|
||||
import { CONSTANTS } from '../constants/constant'
|
||||
|
||||
// 逻辑结构图
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
constructor(opt = {}) {
|
||||
constructor(opt = {}, layout) {
|
||||
super(opt)
|
||||
this.isUseLeft = layout === CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT
|
||||
}
|
||||
|
||||
// 布局
|
||||
@@ -40,8 +42,15 @@ class LogicalStructure extends Base {
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
if (this.isUseLeft) {
|
||||
newNode.left =
|
||||
parent._node.left - newNode.width - this.getMarginX(layerIndex)
|
||||
} else {
|
||||
newNode.left =
|
||||
parent._node.left +
|
||||
parent._node.width +
|
||||
this.getMarginX(layerIndex)
|
||||
}
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
@@ -167,15 +176,24 @@ class LogicalStructure extends Base {
|
||||
}
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
if (this.isUseLeft) {
|
||||
s1 *= -1
|
||||
}
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let x1
|
||||
if (this.isUseLeft) {
|
||||
x1 = node.layerIndex === 0 ? left : left - expandBtnSize
|
||||
} else {
|
||||
x1 = node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
}
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let x2 = this.isUseLeft ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle ? item.width : 0
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle
|
||||
? item.width * (this.isUseLeft ? -1 : 1)
|
||||
: 0
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
let path = this.createFoldLine([
|
||||
@@ -202,15 +220,17 @@ class LogicalStructure extends Base {
|
||||
if (node.layerIndex === 0) {
|
||||
expandBtnSize = 0
|
||||
}
|
||||
let x1 = left + width + expandBtnSize
|
||||
let x1 = this.isUseLeft
|
||||
? left - expandBtnSize
|
||||
: left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let x2 = this.isUseLeft ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
? ` L ${this.isUseLeft ? item.left : item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
this.setLineStyle(style, lines[index], path, item)
|
||||
@@ -235,20 +255,33 @@ class LogicalStructure extends Base {
|
||||
if (node.layerIndex === 0) {
|
||||
expandBtnSize = 0
|
||||
}
|
||||
let x1 =
|
||||
node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve
|
||||
? left + width / 2
|
||||
: left + width + expandBtnSize
|
||||
let x1
|
||||
if (this.isUseLeft) {
|
||||
x1 =
|
||||
node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve
|
||||
? left + width / 2
|
||||
: left - expandBtnSize
|
||||
} else {
|
||||
x1 =
|
||||
node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve
|
||||
? left + width / 2
|
||||
: left + width + expandBtnSize
|
||||
}
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let x2 = this.isUseLeft ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let nodeUseLineStylePath
|
||||
if (this.isUseLeft) {
|
||||
nodeUseLineStylePath = nodeUseLineStyle ? ` L ${item.left},${y2}` : ''
|
||||
} else {
|
||||
nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
}
|
||||
if (node.isRoot && !rootLineKeepSameInCurve) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
@@ -260,14 +293,17 @@ class LogicalStructure extends Base {
|
||||
|
||||
// 渲染按钮
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { width, height, expandBtnSize, layerIndex } = node
|
||||
if (layerIndex === 0) {
|
||||
expandBtnSize = 0
|
||||
}
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
// 位置没有变化则返回
|
||||
let _x = width
|
||||
let _x = this.isUseLeft ? 0 - expandBtnSize : width
|
||||
let _y = height / 2 + nodeUseLineStyleOffset
|
||||
if (_x === translateX && _y === translateY) {
|
||||
return
|
||||
@@ -279,29 +315,42 @@ class LogicalStructure extends Base {
|
||||
renderGeneralization(list) {
|
||||
list.forEach(item => {
|
||||
let {
|
||||
left,
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeGeneralizationRenderBoundaries(item, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let x = this.isUseLeft
|
||||
? left - generalizationLineMargin
|
||||
: right + generalizationLineMargin
|
||||
let x1 = x
|
||||
let y1 = top
|
||||
let x2 = right + generalizationLineMargin
|
||||
let x2 = x
|
||||
let y2 = bottom
|
||||
let cx = x1 + 20
|
||||
let cx = x1 + (this.isUseLeft ? -20 : 20)
|
||||
let cy = y1 + (y2 - y1) / 2
|
||||
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
item.generalizationLine.plot(path)
|
||||
item.generalizationNode.left = right + generalizationNodeMargin
|
||||
item.generalizationNode.left =
|
||||
x +
|
||||
(this.isUseLeft
|
||||
? -generalizationNodeMargin
|
||||
: generalizationNodeMargin) -
|
||||
(this.isUseLeft ? item.generalizationNode.width : 0)
|
||||
item.generalizationNode.top =
|
||||
top + (bottom - top - item.generalizationNode.height) / 2
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染展开收起按钮的隐藏占位元素
|
||||
renderExpandBtnRect(rect, expandBtnSize, width, height, node) {
|
||||
rect.size(expandBtnSize, height).x(width).y(0)
|
||||
renderExpandBtnRect(rect, expandBtnSize, width, height) {
|
||||
if (this.isUseLeft) {
|
||||
rect.size(expandBtnSize, height).x(-expandBtnSize).y(0)
|
||||
} else {
|
||||
rect.size(expandBtnSize, height).x(width).y(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from '../utils'
|
||||
import Base from '../layouts/Base'
|
||||
import { CONSTANTS } from '../constants/constant'
|
||||
import AutoMove from '../utils/AutoMove'
|
||||
|
||||
// 节点拖动插件
|
||||
class Drag extends Base {
|
||||
@@ -13,13 +14,14 @@ class Drag extends Base {
|
||||
constructor({ mindMap }) {
|
||||
super(mindMap.renderer)
|
||||
this.mindMap = mindMap
|
||||
this.autoMove = new AutoMove(mindMap)
|
||||
this.reset()
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 复位
|
||||
reset() {
|
||||
// 是否正在跳转中
|
||||
// 是否正在拖拽中
|
||||
this.isDragging = false
|
||||
// 鼠标按下的节点
|
||||
this.mousedownNode = null
|
||||
@@ -131,7 +133,7 @@ class Drag extends Base {
|
||||
this.mindMap.opt
|
||||
// 停止自动移动
|
||||
if (autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
|
||||
this.mindMap.select.clearAutoMoveTimer()
|
||||
this.autoMove.clearAutoMoveTimer()
|
||||
}
|
||||
this.isMousedown = false
|
||||
// 恢复被拖拽节点的临时设置
|
||||
@@ -148,7 +150,8 @@ class Drag extends Base {
|
||||
const isCancel = await beforeDragEnd({
|
||||
overlapNodeUid,
|
||||
prevNodeUid,
|
||||
nextNodeUid
|
||||
nextNodeUid,
|
||||
beingDragNodeList: [...this.beingDragNodeList]
|
||||
})
|
||||
if (isCancel) {
|
||||
this.reset()
|
||||
@@ -223,7 +226,7 @@ class Drag extends Base {
|
||||
|
||||
// 拖动中
|
||||
onMove(x, y, e) {
|
||||
if (!this.isMousedown) {
|
||||
if (!this.isMousedown || !this.isDragging) {
|
||||
return
|
||||
}
|
||||
// 更新克隆节点的位置
|
||||
@@ -236,18 +239,15 @@ class Drag extends Base {
|
||||
this.clone.translate(x - t.translateX, y - t.translateY)
|
||||
// 检测新位置
|
||||
this.checkOverlapNode()
|
||||
// 如果注册了多选节点插件,那么复用它的边缘自动移动画布功能
|
||||
if (this.mindMap.opt.autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
|
||||
this.drawTransform = this.mindMap.draw.transform()
|
||||
this.mindMap.select.clearAutoMoveTimer()
|
||||
this.mindMap.select.onMove(e.clientX, e.clientY)
|
||||
}
|
||||
// 边缘自动移动画布
|
||||
this.drawTransform = this.mindMap.draw.transform()
|
||||
this.autoMove.clearAutoMoveTimer()
|
||||
this.autoMove.onMove(e.clientX, e.clientY)
|
||||
}
|
||||
|
||||
// 开始拖拽时初始化一些数据
|
||||
handleStartMove() {
|
||||
async handleStartMove() {
|
||||
if (!this.isDragging) {
|
||||
this.isDragging = true
|
||||
// 鼠标按下的节点
|
||||
let node = this.mousedownNode
|
||||
// 计算鼠标按下的位置距离节点左上角的距离
|
||||
@@ -268,12 +268,19 @@ class Drag extends Base {
|
||||
// 否则只拖拽按下的节点
|
||||
this.beingDragNodeList = [node]
|
||||
}
|
||||
// 拦截拖拽
|
||||
const { beforeDragStart } = this.mindMap.opt
|
||||
if (typeof beforeDragStart === 'function') {
|
||||
const stop = await beforeDragStart([...this.beingDragNodeList])
|
||||
if (stop) return
|
||||
}
|
||||
// 将节点树转为节点数组
|
||||
this.nodeTreeToList()
|
||||
// 创建克隆节点
|
||||
this.createCloneNode()
|
||||
// 清除当前所有激活的节点
|
||||
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
||||
this.isDragging = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,6 +397,7 @@ class Drag extends Base {
|
||||
}
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
LOGICAL_STRUCTURE_LEFT,
|
||||
MIND_MAP,
|
||||
ORGANIZATION_STRUCTURE,
|
||||
CATALOG_ORGANIZATION,
|
||||
@@ -413,6 +421,7 @@ class Drag extends Base {
|
||||
}
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case LOGICAL_STRUCTURE:
|
||||
case LOGICAL_STRUCTURE_LEFT:
|
||||
this.handleLogicalStructure(node)
|
||||
break
|
||||
case MIND_MAP:
|
||||
@@ -450,6 +459,7 @@ class Drag extends Base {
|
||||
handleOverlapNode() {
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
LOGICAL_STRUCTURE_LEFT,
|
||||
MIND_MAP,
|
||||
ORGANIZATION_STRUCTURE,
|
||||
CATALOG_ORGANIZATION,
|
||||
@@ -484,6 +494,10 @@ class Drag extends Base {
|
||||
: lastNodeRect.originLeft
|
||||
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
break
|
||||
case LOGICAL_STRUCTURE_LEFT:
|
||||
x = lastNodeRect.originRight - this.placeholderWidth
|
||||
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
break
|
||||
case ORGANIZATION_STRUCTURE:
|
||||
rotate = true
|
||||
x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
|
||||
@@ -596,6 +610,12 @@ class Drag extends Base {
|
||||
nodeRect.originTop +
|
||||
(nodeRect.originHeight - this.placeholderHeight) / 2
|
||||
break
|
||||
case LOGICAL_STRUCTURE_LEFT:
|
||||
x = nodeRect.originLeft - this.placeholderWidth - marginX
|
||||
y =
|
||||
nodeRect.originTop +
|
||||
(nodeRect.originHeight - this.placeholderHeight) / 2
|
||||
break
|
||||
case ORGANIZATION_STRUCTURE:
|
||||
rotate = true
|
||||
x =
|
||||
@@ -676,6 +696,7 @@ class Drag extends Base {
|
||||
getNewChildNodeDir(node) {
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
LOGICAL_STRUCTURE_LEFT,
|
||||
MIND_MAP,
|
||||
TIMELINE2,
|
||||
VERTICAL_TIMELINE,
|
||||
@@ -684,6 +705,8 @@ class Drag extends Base {
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case LOGICAL_STRUCTURE:
|
||||
return CONSTANTS.LAYOUT_GROW_DIR.RIGHT
|
||||
case LOGICAL_STRUCTURE_LEFT:
|
||||
return CONSTANTS.LAYOUT_GROW_DIR.LEFT
|
||||
case MIND_MAP:
|
||||
case TIMELINE2:
|
||||
case VERTICAL_TIMELINE:
|
||||
|
||||
@@ -19,6 +19,7 @@ class MiniMap {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
this.currentState = null
|
||||
}
|
||||
|
||||
// 计算小地图的渲染数据
|
||||
@@ -53,13 +54,16 @@ class MiniMap {
|
||||
let miniMapBoxScale = actWidth / rect.width
|
||||
let miniMapBoxLeft = (boxWidth - actWidth) / 2
|
||||
let miniMapBoxTop = (boxHeight - actHeight) / 2
|
||||
// 视口框大小及位置
|
||||
let _rectX = rect.x - (rect.width * scaleX - rect.width) / 2
|
||||
let _rectX2 = rect.x2 + (rect.width * scaleX - rect.width) / 2
|
||||
let _rectY = rect.y - (rect.height * scaleY - rect.height) / 2
|
||||
let _rectY2 = rect.y2 + (rect.height * scaleY - rect.height) / 2
|
||||
// 当前思维导图图形实际的宽高,即在缩放后的宽高
|
||||
let _rectWidth = rect.width * scaleX
|
||||
let _rectHeight = rect.height * scaleY
|
||||
// 视口框大小及位置
|
||||
let _rectWidthOffsetHalf = (_rectWidth - rect.width) / 2
|
||||
let _rectHeightOffsetHalf = (_rectHeight - rect.height) / 2
|
||||
let _rectX = rect.x - _rectWidthOffsetHalf
|
||||
let _rectX2 = rect.x2 + _rectWidthOffsetHalf
|
||||
let _rectY = rect.y - _rectHeightOffsetHalf
|
||||
let _rectY2 = rect.y2 + _rectHeightOffsetHalf
|
||||
let viewBoxStyle = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
@@ -90,7 +94,14 @@ class MiniMap {
|
||||
})
|
||||
this.removeNodeContent(svg)
|
||||
const svgStr = svg.svg()
|
||||
|
||||
this.currentState = {
|
||||
viewBoxStyle: {
|
||||
...viewBoxStyle
|
||||
},
|
||||
miniMapBoxScale,
|
||||
miniMapBoxLeft,
|
||||
miniMapBoxTop
|
||||
}
|
||||
return {
|
||||
getImgUrl: async callback => {
|
||||
const res = await this.mindMap.doExport.fixSvgStrAndToBlob(svgStr)
|
||||
@@ -141,7 +152,7 @@ class MiniMap {
|
||||
|
||||
// 小地图鼠标移动事件
|
||||
onMousemove(e, sensitivityNum = 5) {
|
||||
if (!this.isMousedown) {
|
||||
if (!this.isMousedown || this.isViewBoxMousedown) {
|
||||
return
|
||||
}
|
||||
let ox = e.clientX - this.mousedownPos.x
|
||||
@@ -154,6 +165,57 @@ class MiniMap {
|
||||
// 小地图鼠标松开事件
|
||||
onMouseup() {
|
||||
this.isMousedown = false
|
||||
this.isViewBoxMousedown = false
|
||||
}
|
||||
|
||||
// 视口框鼠标按下事件
|
||||
onViewBoxMousedown(e) {
|
||||
this.isViewBoxMousedown = true
|
||||
this.mousedownPos = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
}
|
||||
// 保存视图当前的偏移量
|
||||
let transformData = this.mindMap.view.getTransformData()
|
||||
this.startViewPos = {
|
||||
x: transformData.state.x,
|
||||
y: transformData.state.y
|
||||
}
|
||||
}
|
||||
|
||||
// 视口框鼠标移动事件
|
||||
onViewBoxMousemove(e) {
|
||||
if (!this.isViewBoxMousedown || !this.currentState || this.isMousedown)
|
||||
return
|
||||
let ox = e.clientX - this.mousedownPos.x
|
||||
let oy = e.clientY - this.mousedownPos.y
|
||||
const { viewBoxStyle, miniMapBoxScale, miniMapBoxLeft, miniMapBoxTop } =
|
||||
this.currentState
|
||||
const left = Math.max(
|
||||
miniMapBoxLeft,
|
||||
Number.parseFloat(viewBoxStyle.left) + ox
|
||||
)
|
||||
const right = Math.max(
|
||||
miniMapBoxLeft,
|
||||
Number.parseFloat(viewBoxStyle.right) - ox
|
||||
)
|
||||
const top = Math.max(
|
||||
miniMapBoxTop,
|
||||
Number.parseFloat(viewBoxStyle.top) + oy
|
||||
)
|
||||
const bottom = Math.max(
|
||||
miniMapBoxTop,
|
||||
Number.parseFloat(viewBoxStyle.bottom) - oy
|
||||
)
|
||||
this.mindMap.emit('mini_map_view_box_position_change', {
|
||||
left: left + 'px',
|
||||
right: right + 'px',
|
||||
top: top + 'px',
|
||||
bottom: bottom + 'px'
|
||||
})
|
||||
// 在视图最初偏移量上累加更新量
|
||||
this.mindMap.view.translateXTo(-ox / miniMapBoxScale + this.startViewPos.x)
|
||||
this.mindMap.view.translateYTo(-oy / miniMapBoxScale + this.startViewPos.y)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
391
simple-mind-map/src/plugins/OuterFrame.js
Normal file
@@ -0,0 +1,391 @@
|
||||
import {
|
||||
formatDataToArray,
|
||||
walk,
|
||||
getTopAncestorsFomNodeList,
|
||||
getNodeListBoundingRect,
|
||||
createUid
|
||||
} from '../utils'
|
||||
|
||||
// 解析要添加外框的节点实例列表
|
||||
const parseAddNodeList = list => {
|
||||
// 找出顶层节点
|
||||
list = getTopAncestorsFomNodeList(list)
|
||||
const cache = {}
|
||||
const uidToParent = {}
|
||||
// 找出列表中节点在兄弟节点中的索引,并和父节点关联起来
|
||||
list.forEach(node => {
|
||||
const parent = node.parent
|
||||
if (parent) {
|
||||
const pUid = parent.uid
|
||||
uidToParent[pUid] = parent
|
||||
const index = node.getIndexInBrothers()
|
||||
const data = {
|
||||
node,
|
||||
index
|
||||
}
|
||||
if (cache[pUid]) {
|
||||
if (
|
||||
!cache[pUid].find(item => {
|
||||
return item.index === data.index
|
||||
})
|
||||
) {
|
||||
cache[pUid].push(data)
|
||||
}
|
||||
} else {
|
||||
cache[pUid] = [data]
|
||||
}
|
||||
}
|
||||
})
|
||||
const res = []
|
||||
Object.keys(cache).forEach(uid => {
|
||||
const indexList = cache[uid]
|
||||
const parentNode = uidToParent[uid]
|
||||
if (indexList.length > 1) {
|
||||
// 多个节点
|
||||
const rangeList = indexList
|
||||
.map(item => {
|
||||
return item.index
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a - b
|
||||
})
|
||||
const minIndex = rangeList[0]
|
||||
const maxIndex = rangeList[rangeList.length - 1]
|
||||
let curStart = -1
|
||||
let curEnd = -1
|
||||
for (let i = minIndex; i <= maxIndex; i++) {
|
||||
// 连续索引
|
||||
if (rangeList.includes(i)) {
|
||||
if (curStart === -1) {
|
||||
curStart = i
|
||||
}
|
||||
curEnd = i
|
||||
} else {
|
||||
// 连续断开
|
||||
if (curStart !== -1 && curEnd !== -1) {
|
||||
res.push({
|
||||
node: parentNode,
|
||||
range: [curStart, curEnd]
|
||||
})
|
||||
}
|
||||
curStart = -1
|
||||
curEnd = -1
|
||||
}
|
||||
}
|
||||
// 不要忘了最后一段索引
|
||||
if (curStart !== -1 && curEnd !== -1) {
|
||||
res.push({
|
||||
node: parentNode,
|
||||
range: [curStart, curEnd]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 单个节点
|
||||
res.push({
|
||||
node: parentNode,
|
||||
range: [indexList[0].index, indexList[0].index]
|
||||
})
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// 解析获取节点的子节点生成的外框列表
|
||||
const getNodeOuterFrameList = node => {
|
||||
const children = node.children
|
||||
if (!children || children.length <= 0) return
|
||||
const res = []
|
||||
const map = {}
|
||||
children.forEach((item, index) => {
|
||||
const outerFrameData = item.getData('outerFrame')
|
||||
if (!outerFrameData) return
|
||||
const groupId = outerFrameData.groupId
|
||||
if (groupId) {
|
||||
if (!map[groupId]) {
|
||||
map[groupId] = []
|
||||
}
|
||||
map[groupId].push({
|
||||
node: item,
|
||||
index
|
||||
})
|
||||
} else {
|
||||
res.push({
|
||||
nodeList: [item],
|
||||
range: [index, index]
|
||||
})
|
||||
}
|
||||
})
|
||||
Object.keys(map).forEach(id => {
|
||||
const list = map[id]
|
||||
res.push({
|
||||
nodeList: list.map(item => {
|
||||
return item.node
|
||||
}),
|
||||
range: [list[0].index, list[list.length - 1].index]
|
||||
})
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// 默认外框样式
|
||||
const defaultStyle = {
|
||||
radius: 5,
|
||||
strokeWidth: 2,
|
||||
strokeColor: '#0984e3',
|
||||
strokeDasharray: '5,5',
|
||||
fill: 'rgba(9,132,227,0.05)'
|
||||
}
|
||||
|
||||
// 外框插件
|
||||
class OuterFrame {
|
||||
constructor(opt = {}) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.draw = null
|
||||
this.createDrawContainer()
|
||||
this.outerFrameElList = []
|
||||
this.activeOuterFrame = null
|
||||
this.paddingX = 10
|
||||
this.paddingY = 10
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 创建容器
|
||||
createDrawContainer() {
|
||||
this.draw = this.mindMap.draw.group()
|
||||
this.draw.addClass('smm-outer-frame-container')
|
||||
this.draw.back() // 最底层
|
||||
this.draw.forward() // 连线层上面
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
this.renderOuterFrames = this.renderOuterFrames.bind(this)
|
||||
this.mindMap.on('node_tree_render_end', this.renderOuterFrames)
|
||||
this.mindMap.on('data_change', this.renderOuterFrames)
|
||||
// 监听画布和节点点击事件,用于清除当前激活的连接线
|
||||
this.clearActiveOuterFrame = this.clearActiveOuterFrame.bind(this)
|
||||
this.mindMap.on('draw_click', this.clearActiveOuterFrame)
|
||||
this.mindMap.on('node_click', this.clearActiveOuterFrame)
|
||||
|
||||
this.addOuterFrame = this.addOuterFrame.bind(this)
|
||||
this.mindMap.command.add('ADD_OUTER_FRAME', this.addOuterFrame)
|
||||
|
||||
this.removeActiveOuterFrame = this.removeActiveOuterFrame.bind(this)
|
||||
this.mindMap.keyCommand.addShortcut(
|
||||
'Del|Backspace',
|
||||
this.removeActiveOuterFrame
|
||||
)
|
||||
}
|
||||
|
||||
// 解绑事件
|
||||
unBindEvent() {
|
||||
this.mindMap.off('node_tree_render_end', this.renderOuterFrames)
|
||||
this.mindMap.off('data_change', this.renderOuterFrames)
|
||||
this.mindMap.off('draw_click', this.clearActiveOuterFrame)
|
||||
this.mindMap.off('node_click', this.clearActiveOuterFrame)
|
||||
this.mindMap.command.remove('ADD_OUTER_FRAME', this.addOuterFrame)
|
||||
this.mindMap.keyCommand.removeShortcut(
|
||||
'Del|Backspace',
|
||||
this.removeActiveOuterFrame
|
||||
)
|
||||
}
|
||||
|
||||
// 给节点添加外框数据
|
||||
/*
|
||||
config: {
|
||||
text: '',
|
||||
radius: 5,
|
||||
strokeWidth: 2,
|
||||
strokeColor: '#0984e3',
|
||||
strokeDasharray: '5,5',
|
||||
fill: 'rgba(9,132,227,0.05)'
|
||||
}
|
||||
*/
|
||||
addOuterFrame(appointNodes, config = {}) {
|
||||
appointNodes = formatDataToArray(appointNodes)
|
||||
const activeNodeList = this.mindMap.renderer.activeNodeList
|
||||
if (activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||
return
|
||||
}
|
||||
let nodeList = appointNodes.length > 0 ? appointNodes : activeNodeList
|
||||
nodeList = nodeList.filter(node => {
|
||||
return !node.isRoot && !node.isGeneralization
|
||||
})
|
||||
const list = parseAddNodeList(nodeList)
|
||||
list.forEach(({ node, range }) => {
|
||||
const childNodeList = node.children.slice(range[0], range[1] + 1)
|
||||
const groupId = createUid()
|
||||
childNodeList.forEach(child => {
|
||||
let outerFrame = child.getData('outerFrame')
|
||||
// 检查该外框是否已存在
|
||||
if (outerFrame) {
|
||||
outerFrame = {
|
||||
...outerFrame,
|
||||
...config,
|
||||
groupId
|
||||
}
|
||||
} else {
|
||||
outerFrame = {
|
||||
...config,
|
||||
groupId
|
||||
}
|
||||
}
|
||||
this.mindMap.execCommand('SET_NODE_DATA', child, {
|
||||
outerFrame
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 获取当前激活的外框
|
||||
getActiveOuterFrame() {
|
||||
return this.activeOuterFrame
|
||||
? {
|
||||
...this.activeOuterFrame
|
||||
}
|
||||
: null
|
||||
}
|
||||
|
||||
// 删除当前激活的外框
|
||||
removeActiveOuterFrame() {
|
||||
if (!this.activeOuterFrame) return
|
||||
const { node, range } = this.activeOuterFrame
|
||||
this.getRangeNodeList(node, range).forEach(child => {
|
||||
this.mindMap.execCommand('SET_NODE_DATA', child, {
|
||||
outerFrame: null
|
||||
})
|
||||
})
|
||||
this.mindMap.emit('outer_frame_delete')
|
||||
}
|
||||
|
||||
// 更新当前激活的外框
|
||||
// 执行了该方法后请立即隐藏你的样式面板,因为会清除当前激活的外框
|
||||
updateActiveOuterFrame(config = {}) {
|
||||
if (!this.activeOuterFrame) return
|
||||
const { node, range } = this.activeOuterFrame
|
||||
this.getRangeNodeList(node, range).forEach(node => {
|
||||
const outerFrame = node.getData('outerFrame')
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
outerFrame: {
|
||||
...outerFrame,
|
||||
...config
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 获取某个节点指定范围的带外框的子节点列表
|
||||
getRangeNodeList(node, range) {
|
||||
return node.children.slice(range[0], range[1] + 1).filter(child => {
|
||||
return child.getData('outerFrame')
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染外框
|
||||
renderOuterFrames() {
|
||||
this.clearOuterFrameElList()
|
||||
let tree = this.mindMap.renderer.root
|
||||
if (!tree) return
|
||||
const t = this.mindMap.draw.transform()
|
||||
walk(
|
||||
tree,
|
||||
null,
|
||||
cur => {
|
||||
if (!cur) return
|
||||
const outerFrameList = getNodeOuterFrameList(cur)
|
||||
if (outerFrameList && outerFrameList.length > 0) {
|
||||
outerFrameList.forEach(({ nodeList, range }) => {
|
||||
if (range[0] === -1 || range[1] === -1) return
|
||||
const { left, top, width, height } =
|
||||
getNodeListBoundingRect(nodeList)
|
||||
const el = this.createOuterFrameEl(
|
||||
(left - this.paddingX - this.mindMap.elRect.left - t.translateX) /
|
||||
t.scaleX,
|
||||
(top - this.paddingY - this.mindMap.elRect.top - t.translateY) /
|
||||
t.scaleY,
|
||||
(width + this.paddingX * 2) / t.scaleX,
|
||||
(height + this.paddingY * 2) / t.scaleY,
|
||||
nodeList[0].getData('outerFrame') // 使用第一个节点的外框样式
|
||||
)
|
||||
el.on('click', e => {
|
||||
e.stopPropagation()
|
||||
this.setActiveOuterFrame(el, cur, range)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
() => {},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 激活外框
|
||||
setActiveOuterFrame(el, node, range) {
|
||||
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
||||
this.clearActiveOuterFrame()
|
||||
this.activeOuterFrame = {
|
||||
el,
|
||||
node,
|
||||
range
|
||||
}
|
||||
el.stroke({
|
||||
dasharray: 'none'
|
||||
})
|
||||
this.mindMap.emit('outer_frame_active', el, node, range)
|
||||
}
|
||||
|
||||
// 清除当前激活的外框
|
||||
clearActiveOuterFrame() {
|
||||
if (!this.activeOuterFrame) return
|
||||
const { el } = this.activeOuterFrame
|
||||
el.stroke({
|
||||
dasharray: '5,5'
|
||||
})
|
||||
this.activeOuterFrame = null
|
||||
}
|
||||
|
||||
// 创建外框元素
|
||||
createOuterFrameEl(x, y, width, height, styleConfig = {}) {
|
||||
styleConfig = { ...defaultStyle, ...styleConfig }
|
||||
const el = this.draw
|
||||
.rect()
|
||||
.size(width, height)
|
||||
.radius(styleConfig.radius)
|
||||
.stroke({
|
||||
width: styleConfig.strokeWidth,
|
||||
color: styleConfig.strokeColor,
|
||||
dasharray: styleConfig.strokeDasharray
|
||||
})
|
||||
.fill({
|
||||
color: styleConfig.fill
|
||||
})
|
||||
.x(x)
|
||||
.y(y)
|
||||
this.outerFrameElList.push(el)
|
||||
return el
|
||||
}
|
||||
|
||||
// 清除外框元素
|
||||
clearOuterFrameElList() {
|
||||
this.outerFrameElList.forEach(item => {
|
||||
item.remove()
|
||||
})
|
||||
this.outerFrameElList = []
|
||||
this.activeOuterFrame = null
|
||||
}
|
||||
|
||||
// 插件被移除前做的事情
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
OuterFrame.instanceName = 'outerFrame'
|
||||
|
||||
export default OuterFrame
|
||||
@@ -344,7 +344,7 @@ class RichText {
|
||||
// }
|
||||
this.mindMap.render()
|
||||
})
|
||||
this.mindMap.emit('hide_text_edit', this.textEditNode, list)
|
||||
this.mindMap.emit('hide_text_edit', this.textEditNode, list, this.node)
|
||||
this.textEditNode.style.display = 'none'
|
||||
this.showTextEdit = false
|
||||
this.mindMap.emit('rich_text_selection_change', false)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { bfsWalk, throttle, checkTwoRectIsOverlap } from '../utils'
|
||||
import AutoMove from '../utils/AutoMove'
|
||||
|
||||
// 节点选择插件
|
||||
class Select {
|
||||
@@ -13,6 +14,7 @@ class Select {
|
||||
this.mouseMoveY = 0
|
||||
this.isSelecting = false
|
||||
this.cacheActiveList = []
|
||||
this.autoMove = new AutoMove(mindMap)
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
@@ -75,19 +77,21 @@ class Select {
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.clearAutoMoveTimer()
|
||||
this.onMove(
|
||||
this.autoMove.clearAutoMoveTimer()
|
||||
this.autoMove.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]
|
||||
])
|
||||
if (this.rect) {
|
||||
this.rect.plot([
|
||||
[this.mouseDownX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseMoveY],
|
||||
[this.mouseDownX, this.mouseMoveY]
|
||||
])
|
||||
}
|
||||
this.checkInNodes()
|
||||
},
|
||||
(dir, step) => {
|
||||
@@ -120,7 +124,7 @@ class Select {
|
||||
return
|
||||
}
|
||||
this.checkTriggerNodeActiveEvent()
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
this.autoMove.clearAutoMoveTimer()
|
||||
this.isMousedown = false
|
||||
this.cacheActiveList = []
|
||||
if (this.rect) this.rect.remove()
|
||||
@@ -154,54 +158,6 @@ class Select {
|
||||
}
|
||||
}
|
||||
|
||||
// 鼠标移动事件
|
||||
onMove(x, y, callback = () => {}, handle = () => {}) {
|
||||
callback()
|
||||
// 检测边缘移动
|
||||
let step = this.mindMap.opt.selectTranslateStep
|
||||
let limit = this.mindMap.opt.selectTranslateLimit
|
||||
let count = 0
|
||||
// 左边缘
|
||||
if (x <= this.mindMap.elRect.left + limit) {
|
||||
handle('left', step)
|
||||
this.mindMap.view.translateX(step)
|
||||
count++
|
||||
}
|
||||
// 右边缘
|
||||
if (x >= this.mindMap.elRect.right - limit) {
|
||||
handle('right', step)
|
||||
this.mindMap.view.translateX(-step)
|
||||
count++
|
||||
}
|
||||
// 上边缘
|
||||
if (y <= this.mindMap.elRect.top + limit) {
|
||||
handle('top', step)
|
||||
this.mindMap.view.translateY(step)
|
||||
count++
|
||||
}
|
||||
// 下边缘
|
||||
if (y >= this.mindMap.elRect.bottom - limit) {
|
||||
handle('bottom', step)
|
||||
this.mindMap.view.translateY(-step)
|
||||
count++
|
||||
}
|
||||
if (count > 0) {
|
||||
this.startAutoMove(x, y, callback, handle)
|
||||
}
|
||||
}
|
||||
|
||||
// 开启自动移动
|
||||
startAutoMove(x, y, callback, handle) {
|
||||
this.autoMoveTimer = setTimeout(() => {
|
||||
this.onMove(x, y, callback, handle)
|
||||
}, 20)
|
||||
}
|
||||
|
||||
// 清除自动移动定时器
|
||||
clearAutoMoveTimer() {
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
}
|
||||
|
||||
// 创建矩形
|
||||
createRect(x, y) {
|
||||
if (this.rect) this.rect.remove()
|
||||
|
||||
@@ -38,6 +38,7 @@ function createOneControlNode(pointKey) {
|
||||
// 控制点的鼠标按下事件
|
||||
function onControlPointMousedown(e, pointKey) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
this.isControlPointMousedown = true
|
||||
this.mousedownControlPointKey = pointKey
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
lineStyle: 'straight', // 曲线(curve)【仅支持logicalStructure、mindMap、verticalTimeline三种结构】、直线(straight)、直连(direct)【仅支持logicalStructure、mindMap、organizationStructure、verticalTimeline四种结构】
|
||||
// 曲线连接时,根节点和其他节点的连接线样式保持统一,默认根节点为 ( 型,其他节点为 { 型,设为true后,都为 { 型。仅支持logicalStructure、mindMap两种结构
|
||||
rootLineKeepSameInCurve: true,
|
||||
// 曲线连接时,根节点和其他节点的连线起始位置保持统一,默认根节点的连线起始位置在节点中心,其他节点在节点右侧,如果该配置设为true,那么根节点的连线起始位置也会在节点右侧
|
||||
// 曲线连接时,根节点和其他节点的连线起始位置保持统一,默认根节点的连线起始位置在节点中心,其他节点在节点右侧(或左侧),如果该配置设为true,那么根节点的连线起始位置也会在节点右侧(或左侧)
|
||||
rootLineStartPositionKeepSameInCurve: false,
|
||||
// 直线连接(straight)时,连线的圆角大小,设置为0代表没有圆角,仅支持logicalStructure、mindMap、verticalTimeline三种结构
|
||||
lineRadius: 5,
|
||||
|
||||
57
simple-mind-map/src/utils/AutoMove.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// 画布自动移动类
|
||||
class AutoMove {
|
||||
constructor(mindMap) {
|
||||
this.mindMap = mindMap
|
||||
this.autoMoveTimer = null
|
||||
}
|
||||
|
||||
// 鼠标移动事件
|
||||
onMove(x, y, callback = () => {}, handle = () => {}) {
|
||||
callback()
|
||||
// 检测边缘移动
|
||||
let step = this.mindMap.opt.selectTranslateStep
|
||||
let limit = this.mindMap.opt.selectTranslateLimit
|
||||
let count = 0
|
||||
// 左边缘
|
||||
if (x <= this.mindMap.elRect.left + limit) {
|
||||
handle('left', step)
|
||||
this.mindMap.view.translateX(step)
|
||||
count++
|
||||
}
|
||||
// 右边缘
|
||||
if (x >= this.mindMap.elRect.right - limit) {
|
||||
handle('right', step)
|
||||
this.mindMap.view.translateX(-step)
|
||||
count++
|
||||
}
|
||||
// 上边缘
|
||||
if (y <= this.mindMap.elRect.top + limit) {
|
||||
handle('top', step)
|
||||
this.mindMap.view.translateY(step)
|
||||
count++
|
||||
}
|
||||
// 下边缘
|
||||
if (y >= this.mindMap.elRect.bottom - limit) {
|
||||
handle('bottom', step)
|
||||
this.mindMap.view.translateY(-step)
|
||||
count++
|
||||
}
|
||||
if (count > 0) {
|
||||
this.startAutoMove(x, y, callback, handle)
|
||||
}
|
||||
}
|
||||
|
||||
// 开启自动移动
|
||||
startAutoMove(x, y, callback, handle) {
|
||||
this.autoMoveTimer = setTimeout(() => {
|
||||
this.onMove(x, y, callback, handle)
|
||||
}, 20)
|
||||
}
|
||||
|
||||
// 清除自动移动定时器
|
||||
clearAutoMoveTimer() {
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
}
|
||||
}
|
||||
|
||||
export default AutoMove
|
||||
@@ -207,7 +207,7 @@ export const copyNodeTree = (
|
||||
}
|
||||
|
||||
// 图片转成dataURL
|
||||
export const imgToDataUrl = src => {
|
||||
export const imgToDataUrl = (src, returnBlob = false) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||
@@ -220,7 +220,13 @@ export const imgToDataUrl = src => {
|
||||
let ctx = canvas.getContext('2d')
|
||||
// 图片绘制到canvas里
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height)
|
||||
resolve(canvas.toDataURL())
|
||||
if (returnBlob) {
|
||||
canvas.toBlob(blob => {
|
||||
resolve(blob)
|
||||
})
|
||||
} else {
|
||||
resolve(canvas.toDataURL())
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
@@ -1368,7 +1374,8 @@ export const getNodeTreeBoundingRect = (
|
||||
y = 0,
|
||||
paddingX = 0,
|
||||
paddingY = 0,
|
||||
excludeSelf = false
|
||||
excludeSelf = false,
|
||||
excludeGeneralization = false
|
||||
) => {
|
||||
let minX = Infinity
|
||||
let maxX = -Infinity
|
||||
@@ -1392,7 +1399,7 @@ export const getNodeTreeBoundingRect = (
|
||||
maxY = y + height
|
||||
}
|
||||
}
|
||||
if (root._generalizationList.length > 0) {
|
||||
if (!excludeGeneralization && root._generalizationList.length > 0) {
|
||||
root._generalizationList.forEach(item => {
|
||||
walk(item.generalizationNode)
|
||||
})
|
||||
@@ -1418,6 +1425,49 @@ export const getNodeTreeBoundingRect = (
|
||||
}
|
||||
}
|
||||
|
||||
// 获取多个节点总的包围框
|
||||
export const getNodeListBoundingRect = (
|
||||
nodeList,
|
||||
x = 0,
|
||||
y = 0,
|
||||
paddingX = 0,
|
||||
paddingY = 0
|
||||
) => {
|
||||
let minX = Infinity
|
||||
let maxX = -Infinity
|
||||
let minY = Infinity
|
||||
let maxY = -Infinity
|
||||
nodeList.forEach(node => {
|
||||
const { left, top, width, height } = getNodeTreeBoundingRect(
|
||||
node,
|
||||
x,
|
||||
y,
|
||||
paddingX,
|
||||
paddingY,
|
||||
false,
|
||||
true
|
||||
)
|
||||
if (left < minX) {
|
||||
minX = left
|
||||
}
|
||||
if (left + width > maxX) {
|
||||
maxX = left + width
|
||||
}
|
||||
if (top < minY) {
|
||||
minY = top
|
||||
}
|
||||
if (top + height > maxY) {
|
||||
maxY = top + height
|
||||
}
|
||||
})
|
||||
return {
|
||||
left: minX,
|
||||
top: minY,
|
||||
width: maxX - minX,
|
||||
height: maxY - minY
|
||||
}
|
||||
}
|
||||
|
||||
// 全屏事件检测
|
||||
const getOnfullscreEnevt = () => {
|
||||
if (document.documentElement.requestFullScreen) {
|
||||
|
||||
BIN
web/src/assets/avatar/buddy.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
web/src/assets/avatar/lsytyrt.jpg
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
web/src/assets/avatar/秀树因馨雨.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1718261316837') format('woff2'),
|
||||
url('iconfont.woff?t=1718261316837') format('woff'),
|
||||
url('iconfont.ttf?t=1718261316837') format('truetype');
|
||||
src: url('iconfont.woff2?t=1719815803051') format('woff2'),
|
||||
url('iconfont.woff?t=1719815803051') format('woff'),
|
||||
url('iconfont.ttf?t=1719815803051') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,10 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconwaikuang:before {
|
||||
content: "\e640";
|
||||
}
|
||||
|
||||
.iconhighlight:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
BIN
web/src/assets/img/docs/错误.jpg
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
web/src/assets/img/structures/logicalStructureLeft.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
@@ -1,6 +1,7 @@
|
||||
// 布局结构图片映射
|
||||
export const layoutImgMap = {
|
||||
logicalStructure: require('../assets/img/structures/logicalStructure.png'),
|
||||
logicalStructureLeft: require('../assets/img/structures/logicalStructureLeft.jpg'),
|
||||
mindMap: require('../assets/img/structures/mindMap.png'),
|
||||
organizationStructure: require('../assets/img/structures/organizationStructure.png'),
|
||||
catalogOrganization: require('../assets/img/structures/catalogOrganization.png'),
|
||||
@@ -85,9 +86,15 @@ export const formulaList = [
|
||||
]
|
||||
|
||||
export const supportLineStyleLayoutsMap = {
|
||||
curve: ['logicalStructure', 'mindMap', 'verticalTimeline'],
|
||||
curve: [
|
||||
'logicalStructure',
|
||||
'logicalStructureLeft',
|
||||
'mindMap',
|
||||
'verticalTimeline'
|
||||
],
|
||||
direct: [
|
||||
'logicalStructure',
|
||||
'logicalStructureLeft',
|
||||
'mindMap',
|
||||
'organizationStructure',
|
||||
'verticalTimeline'
|
||||
@@ -96,12 +103,14 @@ export const supportLineStyleLayoutsMap = {
|
||||
|
||||
export const supportLineRadiusLayouts = [
|
||||
'logicalStructure',
|
||||
'logicalStructureLeft',
|
||||
'mindMap',
|
||||
'verticalTimeline'
|
||||
]
|
||||
|
||||
export const supportNodeUseLineStyleLayouts = [
|
||||
'logicalStructure',
|
||||
'logicalStructureLeft',
|
||||
'mindMap',
|
||||
'catalogOrganization',
|
||||
'organizationStructure'
|
||||
@@ -109,6 +118,7 @@ export const supportNodeUseLineStyleLayouts = [
|
||||
|
||||
export const supportRootLineKeepSameInCurveLayouts = [
|
||||
'logicalStructure',
|
||||
'logicalStructureLeft',
|
||||
'mindMap'
|
||||
]
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ export const shortcutKeyList = [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: 'Inert child node',
|
||||
value: 'Tab'
|
||||
value: 'Tab | Insert'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
|
||||
@@ -273,7 +273,7 @@ export const shortcutKeyList = [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: '插入下级节点',
|
||||
value: 'Tab'
|
||||
value: 'Tab | Insert'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
|
||||
@@ -63,7 +63,7 @@ export default {
|
||||
isUseHandDrawnLikeStyle: 'Is use hand drawn like style',
|
||||
rootLineStartPos: 'Root line start pos',
|
||||
center: 'Center',
|
||||
right: 'Right',
|
||||
edge: 'Edge',
|
||||
rainbowLines: 'Rainbow lines',
|
||||
notUseRainbowLines: 'Not use rainbow lines'
|
||||
},
|
||||
@@ -100,7 +100,15 @@ export default {
|
||||
removeNote: 'Remove note',
|
||||
removeCustomStyles: 'Remove custom styles',
|
||||
removeAllNodeCustomStyles: 'Remove all node custom styles',
|
||||
exportNodeToPng: 'Export node to png'
|
||||
exportNodeToPng: 'Export node to png',
|
||||
copyToClipboard: 'Copy to clipboard',
|
||||
copyToSmm: 'SMM',
|
||||
copyToJson: 'JSON',
|
||||
copyToMarkdown: 'Markdown',
|
||||
copyToTxt: 'Txt',
|
||||
copyToPng: 'Png',
|
||||
copySuccess: 'Copy success',
|
||||
copyFail: 'Copy fail'
|
||||
},
|
||||
count: {
|
||||
words: 'Words',
|
||||
@@ -266,6 +274,7 @@ export default {
|
||||
painter: 'Painter',
|
||||
formula: 'Formula',
|
||||
attachment: 'Attachment',
|
||||
outerFrame: 'Outer frame',
|
||||
more: 'More',
|
||||
selectFileTip: 'Please select a file',
|
||||
notSupportTip:
|
||||
@@ -357,5 +366,12 @@ export default {
|
||||
lineWidth: 'Line width',
|
||||
padding: 'Padding',
|
||||
animate: 'Animate'
|
||||
},
|
||||
nodeOuterFrame: {
|
||||
outerFrameSetting: 'Setting',
|
||||
deleteOuterFrame: 'Delete outer frame',
|
||||
boxStyle: 'Box style',
|
||||
boxColor: 'Box color',
|
||||
fillColor: 'Fill color'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export default {
|
||||
isUseHandDrawnLikeStyle: '是否开启手绘风格',
|
||||
rootLineStartPos: '根节点连线起始位置',
|
||||
center: '中心',
|
||||
right: '右侧',
|
||||
edge: '边缘',
|
||||
rainbowLines: '彩虹线条',
|
||||
notUseRainbowLines: '不使用彩虹线条'
|
||||
},
|
||||
@@ -100,7 +100,15 @@ export default {
|
||||
removeNote: '移除备注',
|
||||
removeCustomStyles: '一键去除自定义样式',
|
||||
removeAllNodeCustomStyles: '一键去除所有节点自定义样式',
|
||||
exportNodeToPng: '导出该节点为图片'
|
||||
exportNodeToPng: '导出该节点为图片',
|
||||
copyToClipboard: '复制到剪贴板',
|
||||
copyToSmm: 'SMM',
|
||||
copyToJson: 'JSON',
|
||||
copyToMarkdown: 'Markdown',
|
||||
copyToTxt: 'Txt',
|
||||
copyToPng: '图片',
|
||||
copySuccess: '复制成功',
|
||||
copyFail: '复制失败'
|
||||
},
|
||||
count: {
|
||||
words: '字数',
|
||||
@@ -263,6 +271,7 @@ export default {
|
||||
painter: '格式刷',
|
||||
formula: '公式',
|
||||
attachment: '附件',
|
||||
outerFrame: '外框',
|
||||
more: '更多',
|
||||
selectFileTip: '请选择文件',
|
||||
notSupportTip: '你的浏览器不支持该功能,或者当前页面非https协议',
|
||||
@@ -349,5 +358,12 @@ export default {
|
||||
lineWidth: '线宽',
|
||||
padding: '内边距',
|
||||
animate: '开启动画'
|
||||
},
|
||||
nodeOuterFrame: {
|
||||
outerFrameSetting: '外框设置',
|
||||
deleteOuterFrame: '删除外框',
|
||||
boxStyle: '边框样式',
|
||||
boxColor: '边框颜色',
|
||||
fillColor: '填充颜色'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ let APIList = [
|
||||
'handDrawnLikeStyle',
|
||||
'demonstrate',
|
||||
'notation',
|
||||
'outerFrame',
|
||||
'xmind',
|
||||
'markdown',
|
||||
'utils'
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
# Changelog
|
||||
|
||||
## 0.10.2
|
||||
|
||||
> 2024.7.3
|
||||
|
||||
Fix:
|
||||
|
||||
> 1.Fix the issue of node text and custom content with the createNodePrefixContent option not being vertically centered;
|
||||
>
|
||||
> 2.Fix the issue of selecting node text when dragging the endpoints of associated lines;
|
||||
|
||||
New:
|
||||
|
||||
> 1.Add external frame plugins;
|
||||
>
|
||||
> 2.Add a leftward logical structure diagram;
|
||||
>
|
||||
> 3.The mini map supports dragging and dropping view boxes to adjust the canvas position;
|
||||
>
|
||||
> 4.Add an instantiation option to intercept nodes and start dragging them;
|
||||
>
|
||||
> 5.Prevent default behavior for mousedown, mousemove, drag, and node.mousedown events;
|
||||
>
|
||||
> 6.The beforeDragEnd option of the drag plugin adds a callback parameter to the list of nodes that are currently being dragged;
|
||||
>
|
||||
> 7.Add an instantiation option that prohibits reading and writing to the user's clipboard;
|
||||
>
|
||||
> 8.Independently separate the canvas automatic movement function of the Select plugin to solve the problem of the Drag plugin being unable to use the canvas automatic movement function without registering the Select plugin;
|
||||
>
|
||||
> 9.Add callback parameters to the edited node for the hide_text_edit event;
|
||||
>
|
||||
> 10.Activate the node when clicking on the hyperlink icon; Add instantiation options for custom hyperlink redirection;
|
||||
|
||||
Demo:
|
||||
|
||||
> 1.Color selection supports transparency selection;
|
||||
>
|
||||
> 2.Add external frame setting function;
|
||||
>
|
||||
> 3.Add copy to clipboard function in the right-click menu;
|
||||
>
|
||||
> 4.Add a leftward logical structure diagram;
|
||||
>
|
||||
> 5.Fix the issue where the event does not end after the mouse is moved out of the mini map and then released;
|
||||
>
|
||||
> 6.The mini map supports dragging and dropping view boxes to adjust the canvas position;
|
||||
|
||||
## 0.10.1
|
||||
|
||||
Fix:
|
||||
@@ -20,7 +66,7 @@ New:
|
||||
>
|
||||
> 5.Add instantiation options to restrict the maximum and minimum values of TouchEvent plugin's double finger scaling;
|
||||
>
|
||||
> 6.Add a node editing plugin;
|
||||
> 6.Add node marker plugin;
|
||||
|
||||
Demo:
|
||||
|
||||
|
||||
@@ -1,6 +1,37 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.10.2</h2>
|
||||
<blockquote>
|
||||
<p>2024.7.3</p>
|
||||
</blockquote>
|
||||
<p>Fix:</p>
|
||||
<blockquote>
|
||||
<p>1.Fix the issue of node text and custom content with the createNodePrefixContent option not being vertically centered;</p>
|
||||
<p>2.Fix the issue of selecting node text when dragging the endpoints of associated lines;</p>
|
||||
</blockquote>
|
||||
<p>New:</p>
|
||||
<blockquote>
|
||||
<p>1.Add external frame plugins;</p>
|
||||
<p>2.Add a leftward logical structure diagram;</p>
|
||||
<p>3.The mini map supports dragging and dropping view boxes to adjust the canvas position;</p>
|
||||
<p>4.Add an instantiation option to intercept nodes and start dragging them;</p>
|
||||
<p>5.Prevent default behavior for mousedown, mousemove, drag, and node.mousedown events;</p>
|
||||
<p>6.The beforeDragEnd option of the drag plugin adds a callback parameter to the list of nodes that are currently being dragged;</p>
|
||||
<p>7.Add an instantiation option that prohibits reading and writing to the user's clipboard;</p>
|
||||
<p>8.Independently separate the canvas automatic movement function of the Select plugin to solve the problem of the Drag plugin being unable to use the canvas automatic movement function without registering the Select plugin;</p>
|
||||
<p>9.Add callback parameters to the edited node for the hide_text_edit event;</p>
|
||||
<p>10.Activate the node when clicking on the hyperlink icon; Add instantiation options for custom hyperlink redirection;</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
<p>1.Color selection supports transparency selection;</p>
|
||||
<p>2.Add external frame setting function;</p>
|
||||
<p>3.Add copy to clipboard function in the right-click menu;</p>
|
||||
<p>4.Add a leftward logical structure diagram;</p>
|
||||
<p>5.Fix the issue where the event does not end after the mouse is moved out of the mini map and then released;</p>
|
||||
<p>6.The mini map supports dragging and dropping view boxes to adjust the canvas position;</p>
|
||||
</blockquote>
|
||||
<h2>0.10.1</h2>
|
||||
<p>Fix:</p>
|
||||
<blockquote>
|
||||
@@ -14,7 +45,7 @@
|
||||
<p>3.Add a content layout completion event for distributing individual nodes;</p>
|
||||
<p>4.Add instantiation options for intercepting node drag and drop;</p>
|
||||
<p>5.Add instantiation options to restrict the maximum and minimum values of TouchEvent plugin's double finger scaling;</p>
|
||||
<p>6.Add a node editing plugin;</p>
|
||||
<p>6.Add node marker plugin;</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
|
||||
@@ -5,8 +5,20 @@ includes many built-in commands and can also be added manually. A command refers
|
||||
to an operation that needs to add a copy to the history stack data. The
|
||||
`mindMap.command` instance can be obtained through this."
|
||||
|
||||
## Props
|
||||
|
||||
### history
|
||||
|
||||
The current list of all historical data. Do not manually modify the array.
|
||||
|
||||
### activeHistoryIndex
|
||||
|
||||
The current historical data index. Do not manually modify this property.
|
||||
|
||||
## Methods
|
||||
|
||||
Please use the command 'Back' or 'FORWARD' to move forward or backward.
|
||||
|
||||
### pause()
|
||||
|
||||
> v0.9.11+
|
||||
@@ -38,7 +50,7 @@ removed
|
||||
|
||||
### getCopyData()
|
||||
|
||||
Get a copy of the rendering tree data
|
||||
Get a copy of the rendering tree data. That is, the data of the current canvas.
|
||||
|
||||
### clearHistory()
|
||||
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
includes many built-in commands and can also be added manually. A command refers
|
||||
to an operation that needs to add a copy to the history stack data. The
|
||||
<code>mindMap.command</code> instance can be obtained through this."</p>
|
||||
<h2>Props</h2>
|
||||
<h3>history</h3>
|
||||
<p>The current list of all historical data. Do not manually modify the array.</p>
|
||||
<h3>activeHistoryIndex</h3>
|
||||
<p>The current historical data index. Do not manually modify this property.</p>
|
||||
<h2>Methods</h2>
|
||||
<p>Please use the command 'Back' or 'FORWARD' to move forward or backward.</p>
|
||||
<h3>pause()</h3>
|
||||
<blockquote>
|
||||
<p>v0.9.11+</p>
|
||||
@@ -26,7 +32,7 @@ to an operation that needs to add a copy to the history stack data. The
|
||||
<p><code>fn</code>: Method to be removed, if not provided all methods for the command will be
|
||||
removed</p>
|
||||
<h3>getCopyData()</h3>
|
||||
<p>Get a copy of the rendering tree data</p>
|
||||
<p>Get a copy of the rendering tree data. That is, the data of the current canvas.</p>
|
||||
<h3>clearHistory()</h3>
|
||||
<p>Clear the history stack data</p>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const mindMap = new MindMap({
|
||||
| -------------------------------- | ------- | ---------------- | ------------------------------------------- | -------- |
|
||||
| el | Element | | Container element, must be a DOM element(When the position of container elements on the page has changed but the size has not changed, the 'getElRectInfo()' method must be called to update the relevant information inside the library; When the size also changes, the 'resize()' method must be called, otherwise it will cause some functional exceptions) | Yes |
|
||||
| data | Object 、null | | Mind map data, Please refer to the introduction of 【Data structure】 below. V0.9.9+supports passing empty objects or null, and the canvas will display blank space | |
|
||||
| layout | String | logicalStructure | Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timeline(v0.5.4+, timeline)、timeline2(v0.5.4+, up down alternating timeline)、fishbone(v0.5.4+, fishbone diagram) | |
|
||||
| layout | String | logicalStructure | Layout type, options: logicalStructure (logical structure diagram), logicalStructureLeft(v0.10.2+, Leftward logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timeline(v0.5.4+, timeline)、timeline2(v0.5.4+, up down alternating timeline)、fishbone(v0.5.4+, fishbone diagram) | |
|
||||
| fishboneDeg(v0.5.4+) | Number | 45 | Set the diagonal angle of the fishbone structure diagram | |
|
||||
| theme | String | default | Theme, options: default, classic, minions, pinkGrape, mint, gold, vitalityOrange, greenLeaf, dark2, skyGreen, classic2, classic3, classic4(v0.2.0+), classicGreen, classicBlue, blueSky, brainImpairedPink, dark, earthYellow, freshGreen, freshRed, romanticPurple, simpleBlack(v0.5.4+), courseGreen(v0.5.4+), coffee(v0.5.4+), redSpirit(v0.5.4+), blackHumour(v0.5.4+), lateNightOffice(v0.5.4+), blackGold(v0.5.4+)、、avocado(v.5.10-fix.2+)、autumn(v.5.10-fix.2+)、orangeJuice(v.5.10-fix.2+) | |
|
||||
| themeConfig | Object | {} | Theme configuration, will be merged with the selected theme, available fields refer to: [default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
|
||||
@@ -96,6 +96,8 @@ const mindMap = new MindMap({
|
||||
| resetScaleOnMoveNodeToCenter(v0.9.12+) | Boolean | false | Whether to reset the scaling level to 100% when moving nodes to the canvas center, returning to the root node, and other operations(This option actually affects the render. moveNodeToCenter method, and the moveNodeToCenter method itself also has a second parameter, resetScale, to set whether to reset. If the resetScale parameter is not passed, then use resetScaleOnMoveNodeToCenter configuration; otherwise, use resetScale configuration) | |
|
||||
| createNodePrefixContent(v0.9.12+) | Function、null | null | Add additional node pre content.Pre content refers to the pre content in the area of the same line as the text, excluding the node image section.You can pass a function that takes the parameters of a node instance, Can return objects in {el, width, height} format, el is a DOM node object, width and height represent the width, height, and numerical type of the content. If custom content is not required, null can also be returned | |
|
||||
| createNodePostfixContent(v0.9.12+) | Function、null | null | Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section. The usage is the same as createNodePrefixContent | |
|
||||
| disabledClipboard(v0.10.2+) | Boolean | false | Is prohibit pasting data from the user's clipboard and writing copied node data to the user's clipboard. At this time, only node data from the canvas can be copied and pasted | |
|
||||
| customHyperlinkJump(v0.10.2+) | null、Function | false | Customize the jump of hyperlinks. If not passed, the hyperlink will be opened as a new window by default, and a function can be passed, The function takes two parameters: link(The URL of the hyperlink)、node(Node instance to which it belongs), As long as a function is passed, it will block the default jump | |
|
||||
|
||||
### 1.1Data structure
|
||||
|
||||
@@ -214,8 +216,9 @@ new MindMap({
|
||||
| dragPlaceholderRectFill(v0.7.2+) | String | rgb(94, 200, 248) | The filling color of the schematic rectangle for the new position when dragging nodes. | |
|
||||
| dragPlaceholderLineConfig(v0.10.0+) | Object | { color: 'rgb(94, 200, 248)', width: 2 } | Style configuration of schematic lines for new positions when dragging nodes | |
|
||||
| dragOpacityConfig(v0.7.2+) | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node | |
|
||||
| beforeDragEnd(v0.10.1+) | null、Function | null | This function is called just before the drag is completed. The function receives an object as a parameter: {overlapNodeUid,prevNodeUid,nextNodeUid}, represents drag and drop information. If you want to prevent this drag and drop, you can return true. At this time, the node.drag event will not be triggered again. Functions can be asynchronous and return Promise instances | |
|
||||
| beforeDragEnd(v0.10.1+) | null、Function | null | This function is called just before the drag is completed. The function receives an object as a parameter: {overlapNodeUid,prevNodeUid,nextNodeUid,beingDragNodeList}, represents drag and drop information. If you want to prevent this drag and drop, you can return true. At this time, the node.drag event will not be triggered again. Functions can be asynchronous and return Promise instances. 'beingDragNodeList' is a newly added callback parameter for v0.10.2+, which is the list of nodes that are currently being dragged | |
|
||||
| handleDragCloneNode(v0.10.1+) | null、Function | null | When dragging a single node, the dragged node will be cloned. If you want to modify the cloned node, you can provide a processing function through this option, which receives the cloned node object.(It should be noted that the node object refers to the element object of the @svgdotjs/svg.js library, so you need to read the documentation of the library to operate this object) | |
|
||||
| beforeDragStart(v0.10.2+) | null、Function((nodeList) => {}) | null | This function is called just before the node is dragged. The function receives the list of node instances to be dragged as parameters. If you want to prevent this drag, you can return true. It can be an asynchronous function that returns a Promise instance | |
|
||||
|
||||
### 5.Watermark plugin
|
||||
|
||||
@@ -551,7 +554,7 @@ Listen to an event. Event list:
|
||||
| node_active | Node activation event | this (node instance), activeNodeList (current list of active nodes) |
|
||||
| expand_btn_click | Node expand or collapse event | this (node instance) |
|
||||
| before_show_text_edit | Event before node text edit box opens | |
|
||||
| hide_text_edit | Node text edit box close event | textEditNode (text edit box DOM node), activeNodeList (current list of active nodes) |
|
||||
| hide_text_edit | Node text edit box close event【The end of text editing for the associated line will also trigger this event, and there are no callback parameters at this time, so defensive programming is necessary】 | textEditNode (text edit box DOM node), activeNodeList (current list of active nodes) 、node(v0.10.2+, Node instance for current text editing) |
|
||||
| scale | Canvas zoom event | scale (zoom ratio) |
|
||||
| translate(v0.9.10+) | Canvas movement event | x(translate x)、y(translate y) |
|
||||
| node_img_dblclick(v0.2.15+) | Node image double-click event | this (node instance), e (event object) |
|
||||
@@ -585,6 +588,8 @@ Listen to an event. Event list:
|
||||
| demonstrate_jump(v0.9.11+) | Trigger when switching steps in demonstration mode | currentStepIndex(The index of the steps currently played, counting from 0)、stepLength(Total number of playback steps) |
|
||||
| node_tag_click(v0.9.12+) | Click events on node labels | this(Current node instance)、item(Content of clicked tags) |
|
||||
| node_layout_end(v0.10.1+) | Event where the content layout of a single node is completed | this(Current node instance) |
|
||||
| node_attachmentClick(v0.9.10+) | Click event for node attachment icon | this(Current node instance)、e(Event Object)、node(Icon node) |
|
||||
| node_attachmentContextmenu(v0.9.10+) | Right click event on node attachment icon | this(Current node instance)、e(Event Object)、node(Icon node) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<td>layout</td>
|
||||
<td>String</td>
|
||||
<td>logicalStructure</td>
|
||||
<td>Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timeline(v0.5.4+, timeline)、timeline2(v0.5.4+, up down alternating timeline)、fishbone(v0.5.4+, fishbone diagram)</td>
|
||||
<td>Layout type, options: logicalStructure (logical structure diagram), logicalStructureLeft(v0.10.2+, Leftward logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timeline(v0.5.4+, timeline)、timeline2(v0.5.4+, up down alternating timeline)、fishbone(v0.5.4+, fishbone diagram)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -519,6 +519,20 @@
|
||||
<td>Add additional node post content.Post content refers to the post content in the area of the same line as the text, excluding the node image section. The usage is the same as createNodePrefixContent</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>disabledClipboard(v0.10.2+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>Is prohibit pasting data from the user's clipboard and writing copied node data to the user's clipboard. At this time, only node data from the canvas can be copied and pasted</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customHyperlinkJump(v0.10.2+)</td>
|
||||
<td>null、Function</td>
|
||||
<td>false</td>
|
||||
<td>Customize the jump of hyperlinks. If not passed, the hyperlink will be opened as a new window by default, and a function can be passed, The function takes two parameters: link(The URL of the hyperlink)、node(Node instance to which it belongs), As long as a function is passed, it will block the default jump</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>1.1Data structure</h3>
|
||||
@@ -781,7 +795,7 @@
|
||||
<td>beforeDragEnd(v0.10.1+)</td>
|
||||
<td>null、Function</td>
|
||||
<td>null</td>
|
||||
<td>This function is called just before the drag is completed. The function receives an object as a parameter: {overlapNodeUid,prevNodeUid,nextNodeUid}, represents drag and drop information. If you want to prevent this drag and drop, you can return true. At this time, the node.drag event will not be triggered again. Functions can be asynchronous and return Promise instances</td>
|
||||
<td>This function is called just before the drag is completed. The function receives an object as a parameter: {overlapNodeUid,prevNodeUid,nextNodeUid,beingDragNodeList}, represents drag and drop information. If you want to prevent this drag and drop, you can return true. At this time, the node.drag event will not be triggered again. Functions can be asynchronous and return Promise instances. 'beingDragNodeList' is a newly added callback parameter for v0.10.2+, which is the list of nodes that are currently being dragged</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -791,6 +805,13 @@
|
||||
<td>When dragging a single node, the dragged node will be cloned. If you want to modify the cloned node, you can provide a processing function through this option, which receives the cloned node object.(It should be noted that the node object refers to the element object of the @svgdotjs/svg.js library, so you need to read the documentation of the library to operate this object)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>beforeDragStart(v0.10.2+)</td>
|
||||
<td>null、Function((nodeList) => {})</td>
|
||||
<td>null</td>
|
||||
<td>This function is called just before the node is dragged. The function receives the list of node instances to be dragged as parameters. If you want to prevent this drag, you can return true. It can be an asynchronous function that returns a Promise instance</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>5.Watermark plugin</h3>
|
||||
@@ -1438,8 +1459,8 @@ poor performance and should be used sparingly.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hide_text_edit</td>
|
||||
<td>Node text edit box close event</td>
|
||||
<td>textEditNode (text edit box DOM node), activeNodeList (current list of active nodes)</td>
|
||||
<td>Node text edit box close event【The end of text editing for the associated line will also trigger this event, and there are no callback parameters at this time, so defensive programming is necessary】</td>
|
||||
<td>textEditNode (text edit box DOM node), activeNodeList (current list of active nodes) 、node(v0.10.2+, Node instance for current text editing)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scale</td>
|
||||
@@ -1606,6 +1627,16 @@ poor performance and should be used sparingly.</p>
|
||||
<td>Event where the content layout of a single node is completed</td>
|
||||
<td>this(Current node instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_attachmentClick(v0.9.10+)</td>
|
||||
<td>Click event for node attachment icon</td>
|
||||
<td>this(Current node instance)、e(Event Object)、node(Icon node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_attachmentContextmenu(v0.9.10+)</td>
|
||||
<td>Right click event on node attachment icon</td>
|
||||
<td>this(Current node instance)、e(Event Object)、node(Icon node)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## Features
|
||||
|
||||
- [x] Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume
|
||||
- [x] Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures
|
||||
- [x] Support logical structure chart(Left and Right Logical Structure Diagram), mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures
|
||||
- [x] Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes
|
||||
- [x] Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas
|
||||
- [x] Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, Support for expanding node content, and fully customize node content using DDM
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
The official provides the following plugins, which can be introduced as needed (a certain function may not be effective because you did not introduce the corresponding plugin). Please refer to the documentation for specific usage methods:
|
||||
|
||||
> RichText(Node Rich Text Plugin)、Select(Mouse Multiple Selection Node Plugin)、Drag(Node drag plugin)、AssociativeLine(Associate Line Plugin)、Export(Export plugin)、KeyboardNavigation(Keyboard navigation plugin)、MiniMap(Mini Map Plugin)、Watermark(Watermark plugin)、TouchEvent(Mobile touch event support plugin)、NodeImgAdjust(Drag and adjust node image size plugin)、Search(Search plugin)、Painter(Node Format Brush Plugin)、Scrollbar(Scroll bar plugin)、Formula(Mathematical Formula Plugin)、Cooperate(Collaborative editing plugin)、RainbowLines(Rainbow Line Plugin)、Demonstrate(Demonstration mode plugin)、HandDrawnLikeStyle(Hand drawn style plugin)[charge]、Notation(Node marker plugin)[charge]
|
||||
> RichText(Node Rich Text Plugin)、Select(Mouse Multiple Selection Node Plugin)、Drag(Node drag plugin)、AssociativeLine(Associate Line Plugin)、Export(Export plugin)、KeyboardNavigation(Keyboard navigation plugin)、MiniMap(Mini Map Plugin)、Watermark(Watermark plugin)、TouchEvent(Mobile touch event support plugin)、NodeImgAdjust(Drag and adjust node image size plugin)、Search(Search plugin)、Painter(Node Format Brush Plugin)、Scrollbar(Scroll bar plugin)、Formula(Mathematical Formula Plugin)、Cooperate(Collaborative editing plugin)、RainbowLines(Rainbow Line Plugin)、Demonstrate(Demonstration mode plugin)、OuterFrame(Outer frame plugin)、HandDrawnLikeStyle(Hand drawn style plugin)[charge]、Notation(Node marker plugin)[charge]
|
||||
|
||||
Features that will not be implemented in this project:
|
||||
|
||||
@@ -428,4 +428,16 @@ Open source is not easy. If this project is helpful to you, you can invite the a
|
||||
<img src="../../../../assets/avatar/Kyle.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>Kyle</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/lsytyrt.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>lsytyrt</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/秀树因馨雨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>秀树因馨雨</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/buddy.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>buddy</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,22 +8,22 @@
|
||||
</blockquote>
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox68" checked="true" /><label for="checkbox68">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
|
||||
<li><input type="checkbox" id="checkbox69" checked="true" /><label for="checkbox69">Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
|
||||
<li><input type="checkbox" id="checkbox70" checked="true" /><label for="checkbox70">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox71" checked="true" /><label for="checkbox71">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
|
||||
<li><input type="checkbox" id="checkbox72" checked="true" /><label for="checkbox72">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, Support for expanding node content, and fully customize node content using DDM</label></li>
|
||||
<li><input type="checkbox" id="checkbox73" checked="true" /><label for="checkbox73">Support canvas dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox74" checked="true" /><label for="checkbox74">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
|
||||
<li><input type="checkbox" id="checkbox75" checked="true" /><label for="checkbox75">Supoorts to export as </label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>、<code>txt</code>, support import from <code>json</code>、<code>xmind</code>、<code>markdown</code></li>
|
||||
<li><input type="checkbox" id="checkbox76" checked="true" /><label for="checkbox76">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, scrollbar, Hand drawn style, and rainbow lines</label></li>
|
||||
<li><input type="checkbox" id="checkbox77" checked="true" /><label for="checkbox77">Provide rich configurations to meet various scenarios and usage habits</label></li>
|
||||
<li><input type="checkbox" id="checkbox78" checked="true" /><label for="checkbox78">Support collaborative editing</label></li>
|
||||
<li><input type="checkbox" id="checkbox79" checked="true" /><label for="checkbox79">Support demonstration mode</label></li>
|
||||
<li><input type="checkbox" id="checkbox17" checked="true" /><label for="checkbox17">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
|
||||
<li><input type="checkbox" id="checkbox18" checked="true" /><label for="checkbox18">Support logical structure chart(Left and Right Logical Structure Diagram), mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
|
||||
<li><input type="checkbox" id="checkbox19" checked="true" /><label for="checkbox19">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox20" checked="true" /><label for="checkbox20">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
|
||||
<li><input type="checkbox" id="checkbox21" checked="true" /><label for="checkbox21">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, Support for expanding node content, and fully customize node content using DDM</label></li>
|
||||
<li><input type="checkbox" id="checkbox22" checked="true" /><label for="checkbox22">Support canvas dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox23" checked="true" /><label for="checkbox23">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
|
||||
<li><input type="checkbox" id="checkbox24" checked="true" /><label for="checkbox24">Supoorts to export as </label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>、<code>txt</code>, support import from <code>json</code>、<code>xmind</code>、<code>markdown</code></li>
|
||||
<li><input type="checkbox" id="checkbox25" checked="true" /><label for="checkbox25">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, scrollbar, Hand drawn style, and rainbow lines</label></li>
|
||||
<li><input type="checkbox" id="checkbox26" checked="true" /><label for="checkbox26">Provide rich configurations to meet various scenarios and usage habits</label></li>
|
||||
<li><input type="checkbox" id="checkbox27" checked="true" /><label for="checkbox27">Support collaborative editing</label></li>
|
||||
<li><input type="checkbox" id="checkbox28" checked="true" /><label for="checkbox28">Support demonstration mode</label></li>
|
||||
</ul>
|
||||
<p>The official provides the following plugins, which can be introduced as needed (a certain function may not be effective because you did not introduce the corresponding plugin). Please refer to the documentation for specific usage methods:</p>
|
||||
<blockquote>
|
||||
<p>RichText(Node Rich Text Plugin)、Select(Mouse Multiple Selection Node Plugin)、Drag(Node drag plugin)、AssociativeLine(Associate Line Plugin)、Export(Export plugin)、KeyboardNavigation(Keyboard navigation plugin)、MiniMap(Mini Map Plugin)、Watermark(Watermark plugin)、TouchEvent(Mobile touch event support plugin)、NodeImgAdjust(Drag and adjust node image size plugin)、Search(Search plugin)、Painter(Node Format Brush Plugin)、Scrollbar(Scroll bar plugin)、Formula(Mathematical Formula Plugin)、Cooperate(Collaborative editing plugin)、RainbowLines(Rainbow Line Plugin)、Demonstrate(Demonstration mode plugin)、HandDrawnLikeStyle(Hand drawn style plugin)[charge]、Notation(Node marker plugin)[charge]</p>
|
||||
<p>RichText(Node Rich Text Plugin)、Select(Mouse Multiple Selection Node Plugin)、Drag(Node drag plugin)、AssociativeLine(Associate Line Plugin)、Export(Export plugin)、KeyboardNavigation(Keyboard navigation plugin)、MiniMap(Mini Map Plugin)、Watermark(Watermark plugin)、TouchEvent(Mobile touch event support plugin)、NodeImgAdjust(Drag and adjust node image size plugin)、Search(Search plugin)、Painter(Node Format Brush Plugin)、Scrollbar(Scroll bar plugin)、Formula(Mathematical Formula Plugin)、Cooperate(Collaborative editing plugin)、RainbowLines(Rainbow Line Plugin)、Demonstrate(Demonstration mode plugin)、OuterFrame(Outer frame plugin)、HandDrawnLikeStyle(Hand drawn style plugin)[charge]、Notation(Node marker plugin)[charge]</p>
|
||||
</blockquote>
|
||||
<p>Features that will not be implemented in this project:</p>
|
||||
<blockquote>
|
||||
@@ -39,16 +39,16 @@ frameworks such as Vue and React, or without a framework.</p>
|
||||
<p>This is an online mind map built using the <code>simple-mind-map</code> library and based
|
||||
on <code>Vue2.x</code> and <code>ElementUI</code>. Features include:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox80" checked="true" /><label for="checkbox80">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
<li><input type="checkbox" id="checkbox29" checked="true" /><label for="checkbox29">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
images, icons, hyperlinks, notes, tags, and summaries</li>
|
||||
<li><input type="checkbox" id="checkbox81" checked="true" /><label for="checkbox81">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
<li><input type="checkbox" id="checkbox30" checked="true" /><label for="checkbox30">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
outline, theme selection, and structure selection</li>
|
||||
<li><input type="checkbox" id="checkbox82" checked="true" /><label for="checkbox82">Import and export functionality; data is saved in the browser's local</label>
|
||||
<li><input type="checkbox" id="checkbox31" checked="true" /><label for="checkbox31">Import and export functionality; data is saved in the browser's local</label>
|
||||
storage by default, but it also supports creating, opening, and editing
|
||||
local files on the computer directly</li>
|
||||
<li><input type="checkbox" id="checkbox83" checked="true" /><label for="checkbox83">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
<li><input type="checkbox" id="checkbox32" checked="true" /><label for="checkbox32">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
and organizing layout</li>
|
||||
<li><input type="checkbox" id="checkbox84" checked="true" /><label for="checkbox84">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
<li><input type="checkbox" id="checkbox33" checked="true" /><label for="checkbox33">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
between edit and read-only modes, zooming in and out, and switching to
|
||||
full screen, support mini map</li>
|
||||
</ul>
|
||||
@@ -382,6 +382,18 @@ full screen, support mini map</li>
|
||||
<img src="../../../../assets/avatar/Kyle.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>Kyle</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/lsytyrt.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>lsytyrt</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/秀树因馨雨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>秀树因馨雨</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/buddy.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>buddy</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -81,13 +81,16 @@ At this point, when the mind map on the canvas changes, the small map will also
|
||||
be updated in real time, and the view box element will reflect the position of
|
||||
the viewport on the mind map graph in real time
|
||||
|
||||
6.Listen for the `mousedown`, `mousemove`, and `mouseup` events of the
|
||||
`container` element, and call the three methods that will be introduced below to
|
||||
achieve the effect of the mind map on the canvas being dragged with the mouse
|
||||
6.Listen for the `mousedown`, `mousemove`events of the
|
||||
`container` element, And listen for the 'mouseup' event of the 'window' (if 'mouseup' is bound to the 'container' element, the entire dragging behavior of the 'container' element cannot be stopped when the mouse is moved out), and call the three methods that will be introduced below to achieve the effect of the mind map on the canvas being dragged with the mouse
|
||||
|
||||
7.In v0.10.2+version, it supports dragging and dropping viewport boxes within the mini map to achieve synchronized dragging of the canvas, Implementing this feature can listen to the 'mousedown' of the 'viewBoxContainer' element(Need to prevent bubbles, otherwise it will trigger the 'mousedown' event of the 'container' element)、`mousemove` event, Call the 'onViewBoxMousedown' and 'onViewBoxMousemove' methods of the mini map plugin instance separately, At the same time, it is necessary to listen for the 'mini_map_view_box_position_change' event to update the viewBoxContainer element in real-time
|
||||
|
||||
For detailed tutorials, please refer to[How to render a mini map](https://wanglin2.github.io/mind-map/#/doc/zh/course14)。
|
||||
|
||||
### onMousedown(e)
|
||||
|
||||
Small map mouse down event executes this function
|
||||
Small map mouse down event executes this function.
|
||||
|
||||
`e`: event object
|
||||
|
||||
@@ -99,8 +102,20 @@ This function is executed on the small map mouse move event.
|
||||
|
||||
`sensitivityNum`: drag sensitivity, the higher the sensitivity, the greater the
|
||||
actual canvas dragging distance on the small map when dragging the same distance
|
||||
on the small map
|
||||
on the small map.
|
||||
|
||||
### onMouseup()
|
||||
|
||||
This function is executed on the small map mouse release event.
|
||||
This function is executed on the small map mouse release event.
|
||||
|
||||
### onViewBoxMousedown(e)
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
Call this method for the viewport box element mouse down event.
|
||||
|
||||
### onViewBoxMousemove(e)
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
Call this method for the mouse movement event of the viewport box element.
|
||||
@@ -58,20 +58,31 @@ to the <code>miniMapContainer</code> element and set <code>miniMapContainer</cod
|
||||
<p>At this point, when the mind map on the canvas changes, the small map will also
|
||||
be updated in real time, and the view box element will reflect the position of
|
||||
the viewport on the mind map graph in real time</p>
|
||||
<p>6.Listen for the <code>mousedown</code>, <code>mousemove</code>, and <code>mouseup</code> events of the
|
||||
<code>container</code> element, and call the three methods that will be introduced below to
|
||||
achieve the effect of the mind map on the canvas being dragged with the mouse</p>
|
||||
<p>6.Listen for the <code>mousedown</code>, <code>mousemove</code>events of the
|
||||
<code>container</code> element, And listen for the 'mouseup' event of the 'window' (if 'mouseup' is bound to the 'container' element, the entire dragging behavior of the 'container' element cannot be stopped when the mouse is moved out), and call the three methods that will be introduced below to achieve the effect of the mind map on the canvas being dragged with the mouse</p>
|
||||
<p>7.In v0.10.2+version, it supports dragging and dropping viewport boxes within the mini map to achieve synchronized dragging of the canvas, Implementing this feature can listen to the 'mousedown' of the 'viewBoxContainer' element(Need to prevent bubbles, otherwise it will trigger the 'mousedown' event of the 'container' element)、<code>mousemove</code> event, Call the 'onViewBoxMousedown' and 'onViewBoxMousemove' methods of the mini map plugin instance separately, At the same time, it is necessary to listen for the 'mini_map_view_box_position_change' event to update the viewBoxContainer element in real-time</p>
|
||||
<p>For detailed tutorials, please refer to<a href="https://wanglin2.github.io/mind-map/#/doc/zh/course14">How to render a mini map</a>。</p>
|
||||
<h3>onMousedown(e)</h3>
|
||||
<p>Small map mouse down event executes this function</p>
|
||||
<p>Small map mouse down event executes this function.</p>
|
||||
<p><code>e</code>: event object</p>
|
||||
<h3>onMousemove(e, sensitivityNum = 5)</h3>
|
||||
<p>This function is executed on the small map mouse move event.</p>
|
||||
<p><code>e</code>: event object</p>
|
||||
<p><code>sensitivityNum</code>: drag sensitivity, the higher the sensitivity, the greater the
|
||||
actual canvas dragging distance on the small map when dragging the same distance
|
||||
on the small map</p>
|
||||
on the small map.</p>
|
||||
<h3>onMouseup()</h3>
|
||||
<p>This function is executed on the small map mouse release event.</p>
|
||||
<h3>onViewBoxMousedown(e)</h3>
|
||||
<blockquote>
|
||||
<p>v0.10.2+</p>
|
||||
</blockquote>
|
||||
<p>Call this method for the viewport box element mouse down event.</p>
|
||||
<h3>onViewBoxMousemove(e)</h3>
|
||||
<blockquote>
|
||||
<p>v0.10.2+</p>
|
||||
</blockquote>
|
||||
<p>Call this method for the mouse movement event of the viewport box element.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
89
web/src/pages/Doc/en/outerFrame/index.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# OuterFrame plugin
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
This plugin is used to implement bounding box functionality.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
|
||||
MindMap.usePlugin(OuterFrame)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.outerFrame`.
|
||||
|
||||
The application can refer to the code in this section of the demo: [NodeOuterFrame.vue](https://github.com/wanglin2/mind-map/blob/main/web/src/pages/Edit/components/NodeOuterFrame.vue)。
|
||||
|
||||
## Command
|
||||
|
||||
This plugin will register the 'ADD_OUTER_FRAME' command with the mind map to add bounding boxes to nodes:
|
||||
|
||||
```js
|
||||
mindMap.execCommand('ADD_OUTER_FRAME', appointNodes, config = {})
|
||||
```
|
||||
|
||||
- `appointNodes`:Specify the node instance node to add the bounding box to, which can be a single node instance or an array of node instances. If passing '[]' or 'null', the bounding box will be added to the currently active node on the canvas
|
||||
|
||||
- `config`:Outline configuration, object format, and fields are as follows:
|
||||
|
||||
| Field | Type | Default | Desc |
|
||||
| ------------------ | ------- | --------------- | ------------|
|
||||
| radius | Number | 5 | Size of rounded corners on the outer frame |
|
||||
| strokeWidth | Number | 2 | Outer border width |
|
||||
| strokeColor | String | #0984e3 | Outer border color |
|
||||
| strokeDasharray | String | 5,5 | Outer border dashed line |
|
||||
| fill | String | rgba(9,132,227,0.05) | Outer frame fill color |
|
||||
|
||||
## Event
|
||||
|
||||
### outer_frame_active
|
||||
|
||||
Triggered when clicking to activate a certain bounding box. The callback function takes three parameters: el(Outer frame elements,The rect element of library @svgdotjs/svg.js), node(The parent node instance of the node to which this scope belongs), range(Range interval, relative to node)
|
||||
|
||||
The application can listen to this event to retrieve the currently activated bounding box, retrieve its configuration, and echo it to the page. Since the scope may contain multiple nodes, the first node instance is usually taken. If you want to retrieve the position of the bounding box on the page, you can call the 'el.rbox' method:
|
||||
|
||||
```js
|
||||
mindMap.on('outer_frame_active', (el, parentNode, range) => {
|
||||
// Take the bounding box style of the first node within the range
|
||||
const firstNode = parentNode.children[range[0]]
|
||||
const firstNodeOuterFrame = firstNode.getData('outerFrame')
|
||||
// Obtain the position and size information of the bounding box, where you can render your configuration float layer
|
||||
const { x, y, width, height } = el.rbox()
|
||||
})
|
||||
```
|
||||
|
||||
### outer_frame_delete
|
||||
|
||||
Triggered when deleting the currently active bounding box on the canvas.
|
||||
|
||||
## Methods
|
||||
|
||||
### getActiveOuterFrame()
|
||||
|
||||
Get the currently activated bounding box data. Return an object with the following structure:
|
||||
|
||||
```js
|
||||
{
|
||||
el,
|
||||
node,
|
||||
range
|
||||
}
|
||||
```
|
||||
|
||||
### updateActiveOuterFrame(config = {})
|
||||
|
||||
Update the currently active bounding box. After executing this method, please immediately hide your style panel as it will clear the currently active bounding box.
|
||||
|
||||
### removeActiveOuterFrame()
|
||||
|
||||
Delete the currently active bounding box.
|
||||
|
||||
### getRangeNodeList(node, range)
|
||||
|
||||
Get a list of boxed child nodes within a specified range of a node.
|
||||
|
||||
### clearActiveOuterFrame()
|
||||
|
||||
Clear the currently active bounding box.
|
||||
112
web/src/pages/Doc/en/outerFrame/index.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>OuterFrame plugin</h1>
|
||||
<blockquote>
|
||||
<p>v0.10.2+</p>
|
||||
</blockquote>
|
||||
<p>This plugin is used to implement bounding box functionality.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> OuterFrame <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/plugins/OuterFrame.js'</span>
|
||||
MindMap.usePlugin(OuterFrame)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.outerFrame</code>.</p>
|
||||
<p>The application can refer to the code in this section of the demo: <a href="https://github.com/wanglin2/mind-map/blob/main/web/src/pages/Edit/components/NodeOuterFrame.vue">NodeOuterFrame.vue</a>。</p>
|
||||
<h2>Command</h2>
|
||||
<p>This plugin will register the 'ADD_OUTER_FRAME' command with the mind map to add bounding boxes to nodes:</p>
|
||||
<pre class="hljs"><code>mindMap.execCommand(<span class="hljs-string">'ADD_OUTER_FRAME'</span>, appointNodes, config = {})
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>appointNodes</code>:Specify the node instance node to add the bounding box to, which can be a single node instance or an array of node instances. If passing '[]' or 'null', the bounding box will be added to the currently active node on the canvas</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>config</code>:Outline configuration, object format, and fields are as follows:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Default</th>
|
||||
<th>Desc</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>radius</td>
|
||||
<td>Number</td>
|
||||
<td>5</td>
|
||||
<td>Size of rounded corners on the outer frame</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>strokeWidth</td>
|
||||
<td>Number</td>
|
||||
<td>2</td>
|
||||
<td>Outer border width</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>strokeColor</td>
|
||||
<td>String</td>
|
||||
<td>#0984e3</td>
|
||||
<td>Outer border color</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>strokeDasharray</td>
|
||||
<td>String</td>
|
||||
<td>5,5</td>
|
||||
<td>Outer border dashed line</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>fill</td>
|
||||
<td>String</td>
|
||||
<td>rgba(9,132,227,0.05)</td>
|
||||
<td>Outer frame fill color</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Event</h2>
|
||||
<h3>outer_frame_active</h3>
|
||||
<p>Triggered when clicking to activate a certain bounding box. The callback function takes three parameters: el(Outer frame elements,The rect element of library @svgdotjs/svg.js), node(The parent node instance of the node to which this scope belongs), range(Range interval, relative to node)</p>
|
||||
<p>The application can listen to this event to retrieve the currently activated bounding box, retrieve its configuration, and echo it to the page. Since the scope may contain multiple nodes, the first node instance is usually taken. If you want to retrieve the position of the bounding box on the page, you can call the 'el.rbox' method:</p>
|
||||
<pre class="hljs"><code>mindMap.on(<span class="hljs-string">'outer_frame_active'</span>, <span class="hljs-function">(<span class="hljs-params">el, parentNode, range</span>) =></span> {
|
||||
<span class="hljs-comment">// Take the bounding box style of the first node within the range</span>
|
||||
<span class="hljs-keyword">const</span> firstNode = parentNode.children[range[<span class="hljs-number">0</span>]]
|
||||
<span class="hljs-keyword">const</span> firstNodeOuterFrame = firstNode.getData(<span class="hljs-string">'outerFrame'</span>)
|
||||
<span class="hljs-comment">// Obtain the position and size information of the bounding box, where you can render your configuration float layer</span>
|
||||
<span class="hljs-keyword">const</span> { x, y, width, height } = el.rbox()
|
||||
})
|
||||
</code></pre>
|
||||
<h3>outer_frame_delete</h3>
|
||||
<p>Triggered when deleting the currently active bounding box on the canvas.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>getActiveOuterFrame()</h3>
|
||||
<p>Get the currently activated bounding box data. Return an object with the following structure:</p>
|
||||
<pre class="hljs"><code>{
|
||||
el,
|
||||
node,
|
||||
range
|
||||
}
|
||||
</code></pre>
|
||||
<h3>updateActiveOuterFrame(config = {})</h3>
|
||||
<p>Update the currently active bounding box. After executing this method, please immediately hide your style panel as it will clear the currently active bounding box.</p>
|
||||
<h3>removeActiveOuterFrame()</h3>
|
||||
<p>Delete the currently active bounding box.</p>
|
||||
<h3>getRangeNodeList(node, range)</h3>
|
||||
<p>Get a list of boxed child nodes within a specified range of a node.</p>
|
||||
<h3>clearActiveOuterFrame()</h3>
|
||||
<p>Clear the currently active bounding box.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -209,3 +209,15 @@ Different packaging tools may have different specific configurations, with the p
|
||||
### When clicking the [New], [Open], or [Save As] buttons, it will prompt that the browser does not support it or is not using the HTTPS protocol.
|
||||
|
||||
The browser uses API [window.showOpenFilePicker](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/showOpenFilePicker) to operate local files on the computer. If it is not supported, either the browser does not support this API or the page is not using the HTTPS protocol, You can press F12, or open the browser console through the right-click menu on the page and enter 'window.showOpenFilePicker' in the 'Console' tab. If it returns 'undefined', it means it is not supported. If it does not return this message and the page still prompts that the browser does not support it or is not using the HTTPS protocol, you can submit an issue or contact the author.
|
||||
|
||||
### 5.Import simple-mind-map error message, the error message is as follows:
|
||||
|
||||
<img src="../../../../assets/img/docs/错误.jpg" style="width: 850px" />
|
||||
|
||||
This is because your build environment does not support this JavaScript syntax, which comes from the '@svgdotjs/svg.js' library. The solution is as follows:
|
||||
|
||||
1.Manually reduce the version of the '@svgdotjs/svg.js' library. You can manually install the lower version in your project, such as: `npm i @svgdotjs/svg.js@3.0.16`
|
||||
|
||||
2.If you don't reduce the version, you can modify the relevant configuration of your build tool, modify the configuration of 'babel', and have it compile the 'simple-mind-map' library in 'node.modules' or the '@svgdotjs/svg.js' library. If you are using 'vue-cli' or 'vite', they also provide the relevant configuration directly. In addition, it is necessary to install the 'babel' plugin that compiles this syntax and configure it in the 'babel' configuration file:
|
||||
|
||||
`@babel/plugin-proposal-nullish-coalescing-operator`、`@babel/plugin-proposal-optional-chaining`。
|
||||
@@ -1,146 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Start</h1>
|
||||
<h2>Installation</h2>
|
||||
<blockquote>
|
||||
<p>Things to note before version 0.2.0:</p>
|
||||
</blockquote>
|
||||
<pre class="hljs"><code>npm i simple-mind-map
|
||||
</code></pre>
|
||||
<p><code>0.2.0</code> Notes for previous versions:</p>
|
||||
<blockquote>
|
||||
<p>Note: This project is directly published in source code form and has not been
|
||||
packaged. If compilation fails, a Vue CLI-created project can add the
|
||||
following configuration to the vue.config.js file to allow babel-loader to
|
||||
compile this dependency:</p>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = {
|
||||
<span class="hljs-attr">transpileDependencies</span>: [<span class="hljs-string">"simple-mind-map"</span>],
|
||||
};
|
||||
</code></pre>
|
||||
<p>Other projects should modify the packaging configuration as needed.</p>
|
||||
</blockquote>
|
||||
<h2>Usage</h2>
|
||||
<blockquote>
|
||||
<p>The <code>web</code> directory of this repository provides a complete project based on <code>Vue2</code>. If you encounter any doubts about using it, you can refer to the implementation of this project.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>To learn about its use in other frameworks, you can refer to the following unofficial implementations:</p>
|
||||
<p>1.<a href="https://github.com/huangyuanyin/hyy-vue3-mindMap">https://github.com/huangyuanyin/hyy-vue3-mindMap</a>: A mind map based on Vue3.2+ElementPlus.</p>
|
||||
</blockquote>
|
||||
<p>Firstly, provide a container element with a width and height not equal to 0:</p>
|
||||
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mindMapContainer"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>
|
||||
</code></pre>
|
||||
<p>Also, set the <code>CSS</code> style again:</p>
|
||||
<pre class="hljs"><code><span class="hljs-selector-id">#mindMapContainer</span> * {
|
||||
<span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
|
||||
<span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
|
||||
}
|
||||
</code></pre>
|
||||
<p>Then introduce the <code>simple-mind-map</code> library and create an instance:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map"</span>;
|
||||
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">el</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'mindMapContainer'</span>),
|
||||
<span class="hljs-attr">data</span>: {
|
||||
<span class="hljs-string">"data"</span>: {
|
||||
<span class="hljs-string">"text"</span>: <span class="hljs-string">"Root Node"</span>
|
||||
},
|
||||
<span class="hljs-string">"children"</span>: []
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
<p>This will result in a mind map.</p>
|
||||
<p>If you want to implement a complete mind map, you usually need to develop some UI interfaces to achieve more functions through the interfaces provided by the <code>simple-mind-map</code> library.</p>
|
||||
<p><code>simple-mind-map</code> supports rich configurations, events, commands, and some additional plugin extensions. Read the subsequent documentation to learn more.</p>
|
||||
<p>The non-packaged 'ES' module is introduced by default, and only contains core functions, not unregistered plugin content, which can effectively reduce the size. However, you need to configure the <code>babel</code> compilation <code>simple mind-map</code> in your project to prevent some newer <code>js</code> syntax some browsers not supporting it.</p>
|
||||
<p>If you don't want to load all plugins from the beginning and want to load and register plugins asynchronously after instantiation, you can do this:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span>(<span class="hljs-string">'simple-mind-map/src/plugins/Export.js'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {
|
||||
mindMap.addPlugin(res.default)
|
||||
})
|
||||
</code></pre>
|
||||
<p>If you need a file in the format of <code>umd</code> module, such as <code>CDN</code> in the browser, Then you can find the <code>simpleMindMap.umd.min.js</code> file and <code>simpleMindMap.css</code> file in the <code>/simple-mind-map/dist/</code> directory, copy it to your project, and then import it into the page:</p>
|
||||
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"simpleMindMap.css"</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">scr</span>=<span class="hljs-string">"simpleMindMap.umd.min.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
|
||||
</code></pre>
|
||||
<p>A global variable <code>window.simpleMindMap</code> will be created. you can get <code>MindMap</code> constructor by <code>window.simpleMindMap.default</code>, for more detail info you can log <code>window.simpleMindMap</code>.</p>
|
||||
<p>The disadvantage of this method is that it will contain all the content, including the plugins you have not registered, so the overall volume will be relatively large.</p>
|
||||
<p>(v0.5.4+)If you want to use the <code>ES</code> module directly on the browser side, you can find the <code>simpleMindMap.esm.js</code> and <code>simpleMindMap.esm.css</code> files in the <code>/simple-mind-map/dist/</code> directory.</p>
|
||||
<p>Online CDN services can also be used, such as:</p>
|
||||
<pre class="hljs"><code>https://unpkg.com/browse/simple-mind-map@0.9.2/dist/
|
||||
</code></pre>
|
||||
<p>You can find all the packaged files for a certain version.</p>
|
||||
<h2>Development</h2>
|
||||
<p>If you only use library, you don't need to read this section.</p>
|
||||
<h3>Local Development</h3>
|
||||
<pre class="hljs"><code>git <span class="hljs-built_in">clone</span> https://github.com/wanglin2/mind-map.git
|
||||
<span class="hljs-built_in">cd</span> mind-map
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
<span class="hljs-built_in">cd</span> ..
|
||||
<span class="hljs-built_in">cd</span> web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
npm run serve
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>If there is an installation dependency error, you can try adjusting the node version. The author is using version 14. x.</p>
|
||||
</blockquote>
|
||||
<h3>Packaging the Library</h3>
|
||||
<p>Since version <code>0.2.0</code>, we have added support for packaging the core library
|
||||
simple-mind-map. This uses the same packaging tool as the sample project web.</p>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run buildLibrary
|
||||
</code></pre>
|
||||
<p>The packaging entry is <code>simple-mind-map/full.js</code>, which will introduce all plugins by default. If you don't need all plugins, you can modify the file to only introduce the plugins you need, which can reduce the size of the packaged file.</p>
|
||||
<p>The <code>package.json</code> file in the <code>simple-mind-map</code> library provides two export
|
||||
fields:</p>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">"module"</span>: <span class="hljs-string">"index.js"</span>,
|
||||
<span class="hljs-attr">"main"</span>: <span class="hljs-string">"./dist/simpleMindMap.umd.min.js"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Environments that support the <code>module</code> field will use <code>index.js</code> as the entry
|
||||
point, otherwise the packed <code>simpleMindMap.umd.min.js</code> will be used as the entry
|
||||
point.</p>
|
||||
<h4>Generate TypeScript type files</h4>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm run types
|
||||
</code></pre>
|
||||
<p>You can obtain the type files in the 'simple-mind-map/types/' directory.</p>
|
||||
<h3>Compile the doc</h3>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run buildDoc
|
||||
</code></pre>
|
||||
<h3>Packaging the Demo</h3>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run build
|
||||
</code></pre>
|
||||
<p>The <code>index.html</code> file will be automatically moved to the root directory.</p>
|
||||
<h2>Problems</h2>
|
||||
<h3>Error when using in Vite, indicating xml-js dependency error</h3>
|
||||
<p>Solution: use the following import method:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map/dist/simpleMindMap.umd.min"</span>;
|
||||
</code></pre>
|
||||
<p>The <code>simple-mind-map</code> package provides the unpacked entry field <code>module</code>, and
|
||||
the <code>xml-js</code> package dependency needs to import the package in the <code>node</code>
|
||||
environment. Therefore, it cannot be obtained in <code>Vite</code> and an error will be
|
||||
reported. Therefore, specify the import of the packed entry, and all relevant
|
||||
packages are packed into the product, so there will be no error.</p>
|
||||
<p>If you need to do further development, that is, you must use the unpacked code,
|
||||
and if you do not need to parse the <code>xmind</code> file, you can remove the <code>xmind</code>
|
||||
module. If you need it, you can try using other libraries to parse <code>xml</code> to
|
||||
<code>json</code>.</p>
|
||||
<h3>Error <code>Getting bbox of element "text" is not possible: TypeError: Cannot read properties of undefined (reading 'apply')</code></h3>
|
||||
<p>The reason is that the installed version of <code>@svgdotjs/svg.js</code> is too high. You can manually reduce it to the version of <code>3.0.16</code>.</p>
|
||||
<h3>TypeError: Cannot read properties of undefined (reading 'prototype') at sax.js:222:46</h3>
|
||||
<p>The following configurations can be added to the packaging configuration file:</p>
|
||||
<pre class="hljs"><code>resolve: { <span class="hljs-attr">alias</span>: { <span class="hljs-attr">stream</span>: <span class="hljs-string">"stream-browserify"</span> } }
|
||||
</code></pre>
|
||||
<p>Different packaging tools may have different specific configurations, with the principle of excluding 'stream' dependencies.</p>
|
||||
<h3>When clicking the [New], [Open], or [Save As] buttons, it will prompt that the browser does not support it or is not using the HTTPS protocol.</h3>
|
||||
<p>The browser uses API <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/showOpenFilePicker">window.showOpenFilePicker</a> to operate local files on the computer. If it is not supported, either the browser does not support this API or the page is not using the HTTPS protocol, You can press F12, or open the browser console through the right-click menu on the page and enter 'window.showOpenFilePicker' in the 'Console' tab. If it returns 'undefined', it means it is not supported. If it does not return this message and the page still prompts that the browser does not support it or is not using the HTTPS protocol, you can submit an issue or contact the author.</p>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -101,7 +101,11 @@ and copying the `data` of the data object, example:
|
||||
copyNodeTree({}, node);
|
||||
```
|
||||
|
||||
#### imgToDataUrl(src)
|
||||
#### imgToDataUrl(src, returnBlob = false)
|
||||
|
||||
- `src`:Image url
|
||||
|
||||
- `returnBlob`:v0.10.2+,Is the result returned in Blob format, defaulting to DataURL format
|
||||
|
||||
Convert image to dataURL
|
||||
|
||||
|
||||
@@ -66,7 +66,15 @@ basic data, otherwise it will throw an error</p>
|
||||
and copying the <code>data</code> of the data object, example:</p>
|
||||
<pre class="hljs"><code>copyNodeTree({}, node);
|
||||
</code></pre>
|
||||
<h4>imgToDataUrl(src)</h4>
|
||||
<h4>imgToDataUrl(src, returnBlob = false)</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>src</code>:Image url</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>returnBlob</code>:v0.10.2+,Is the result returned in Blob format, defaulting to DataURL format</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Convert image to dataURL</p>
|
||||
<h4>downloadFile(file, fileName)</h4>
|
||||
<p>Download file</p>
|
||||
|
||||
@@ -70,6 +70,8 @@ getTransformData method"
|
||||
|
||||
> v0.2.17+
|
||||
|
||||
- `scale`: Scaling values, not scaled to '1', scaled to '1' for values less than, scaled to '1' for values greater than, scaled to '1' for values greater than
|
||||
|
||||
- `cx`:(v0.6.4+)Zoom to the specified position on the canvas, default to the center point of the canvas
|
||||
|
||||
- `cy`:(v0.6.4+)Zoom to the specified position on the canvas, default to the center point of the canvas
|
||||
|
||||
@@ -63,6 +63,9 @@ getTransformData method"</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>scale</code>: Scaling values, not scaled to '1', scaled to '1' for values less than, scaled to '1' for values greater than, scaled to '1' for values greater than</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>cx</code>:(v0.6.4+)Zoom to the specified position on the canvas, default to the center point of the canvas</p>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -65,6 +65,7 @@ export default [
|
||||
{ path: 'cooperate', title: 'Cooperate插件' },
|
||||
{ path: 'rainbowLines', title: 'RainbowLines插件' },
|
||||
{ path: 'demonstrate', title: 'Demonstrate插件' },
|
||||
{ path: 'outerFrame', title: 'OuterFrame插件' },
|
||||
{ path: 'handDrawnLikeStyle', title: 'HandDrawnLikeStyle收费插件' },
|
||||
{ path: 'notation', title: 'Notation收费插件' },
|
||||
{ path: 'help1', title: '概要/关联线' },
|
||||
@@ -111,6 +112,7 @@ export default [
|
||||
{ path: 'cooperate', title: 'Cooperate plugin' },
|
||||
{ path: 'rainbowLines', title: 'RainbowLines plugin' },
|
||||
{ path: 'demonstrate', title: 'Demonstrate plugin' },
|
||||
{ path: 'outerFrame', title: 'OuterFrame plugin' },
|
||||
{
|
||||
path: 'handDrawnLikeStyle',
|
||||
title: 'HandDrawnLikeStyle chargeable plugin'
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
# Changelog
|
||||
|
||||
## 0.10.2
|
||||
|
||||
> 2024.7.3
|
||||
|
||||
修复:
|
||||
|
||||
> 1.修复节点文本和createNodePrefixContent选项自定义的内容没有垂直居中的问题;
|
||||
>
|
||||
> 2.修复拖动关联线端点移动时会选中节点文字的问题;
|
||||
|
||||
新增:
|
||||
|
||||
> 1.新增外框插件;
|
||||
>
|
||||
> 2.新增向左逻辑结构图;
|
||||
>
|
||||
> 3.小地图支持拖拽视图框调整画布位置;
|
||||
>
|
||||
> 4.新增拦截节点开始拖拽的实例化选项;
|
||||
>
|
||||
> 5.阻止mousedown、mousemove、drag、node_mousedown事件的默认行为;
|
||||
>
|
||||
> 6.drag插件的beforeDragEnd选项新增当前被拖拽的节点列表的回调参数;
|
||||
>
|
||||
> 7.新增禁止读取和写入用户剪贴板的实例化选项;
|
||||
>
|
||||
> 8.将Select插件的画布自动移动功能独立出来,解决没有注册Select插件的情况下Drag插件无法使用画布自动移动功能的问题;
|
||||
>
|
||||
> 9.hide_text_edit事件增加被编辑节点的回调参数;
|
||||
>
|
||||
> 10.点击超链接图标时激活节点;新增自定义超链接跳转的实例化选项;
|
||||
|
||||
Demo:
|
||||
|
||||
> 1.颜色选择支持选择透明度;
|
||||
>
|
||||
> 2.新增外框设置功能;
|
||||
>
|
||||
> 3.右键菜单新增复制到剪贴板功能;
|
||||
>
|
||||
> 4.新增向左逻辑结构图;
|
||||
>
|
||||
> 5.修复鼠标移出小地图再松开后事件没有结束的问题;
|
||||
>
|
||||
> 6.小地图支持拖拽视图框调整画布位置;
|
||||
|
||||
## 0.10.1
|
||||
|
||||
修复:
|
||||
@@ -20,7 +66,7 @@
|
||||
>
|
||||
> 5.新增限制TouchEvent插件双指缩放的最大值和最小值的实例化选项;
|
||||
>
|
||||
> 6.新增节点编辑插件;
|
||||
> 6.新增节点标记插件;
|
||||
|
||||
Demo:
|
||||
|
||||
|
||||
@@ -1,6 +1,37 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.10.2</h2>
|
||||
<blockquote>
|
||||
<p>2024.7.3</p>
|
||||
</blockquote>
|
||||
<p>修复:</p>
|
||||
<blockquote>
|
||||
<p>1.修复节点文本和createNodePrefixContent选项自定义的内容没有垂直居中的问题;</p>
|
||||
<p>2.修复拖动关联线端点移动时会选中节点文字的问题;</p>
|
||||
</blockquote>
|
||||
<p>新增:</p>
|
||||
<blockquote>
|
||||
<p>1.新增外框插件;</p>
|
||||
<p>2.新增向左逻辑结构图;</p>
|
||||
<p>3.小地图支持拖拽视图框调整画布位置;</p>
|
||||
<p>4.新增拦截节点开始拖拽的实例化选项;</p>
|
||||
<p>5.阻止mousedown、mousemove、drag、node_mousedown事件的默认行为;</p>
|
||||
<p>6.drag插件的beforeDragEnd选项新增当前被拖拽的节点列表的回调参数;</p>
|
||||
<p>7.新增禁止读取和写入用户剪贴板的实例化选项;</p>
|
||||
<p>8.将Select插件的画布自动移动功能独立出来,解决没有注册Select插件的情况下Drag插件无法使用画布自动移动功能的问题;</p>
|
||||
<p>9.hide_text_edit事件增加被编辑节点的回调参数;</p>
|
||||
<p>10.点击超链接图标时激活节点;新增自定义超链接跳转的实例化选项;</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
<p>1.颜色选择支持选择透明度;</p>
|
||||
<p>2.新增外框设置功能;</p>
|
||||
<p>3.右键菜单新增复制到剪贴板功能;</p>
|
||||
<p>4.新增向左逻辑结构图;</p>
|
||||
<p>5.修复鼠标移出小地图再松开后事件没有结束的问题;</p>
|
||||
<p>6.小地图支持拖拽视图框调整画布位置;</p>
|
||||
</blockquote>
|
||||
<h2>0.10.1</h2>
|
||||
<p>修复:</p>
|
||||
<blockquote>
|
||||
@@ -14,7 +45,7 @@
|
||||
<p>3.新增派发单个节点的内容布局完成事件;</p>
|
||||
<p>4.新增拦截节点拖拽的实例化选项;</p>
|
||||
<p>5.新增限制TouchEvent插件双指缩放的最大值和最小值的实例化选项;</p>
|
||||
<p>6.新增节点编辑插件;</p>
|
||||
<p>6.新增节点标记插件;</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
|
||||
@@ -2,8 +2,20 @@
|
||||
|
||||
`command`实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过`mindMap.command`获取到该实例
|
||||
|
||||
## 属性
|
||||
|
||||
### history
|
||||
|
||||
当前所有的历史数据列表。不要手动修改该数组。
|
||||
|
||||
### activeHistoryIndex
|
||||
|
||||
当前所在的历史数据索引。不要手动修改该属性。
|
||||
|
||||
## 方法
|
||||
|
||||
前进后退请使用命令`BACK`或`FORWARD`。
|
||||
|
||||
### pause()
|
||||
|
||||
> v0.9.11+
|
||||
@@ -34,7 +46,7 @@
|
||||
|
||||
### getCopyData()
|
||||
|
||||
获取渲染树数据副本
|
||||
获取渲染树数据副本。即当前画布的数据。
|
||||
|
||||
### clearHistory()
|
||||
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
<div>
|
||||
<h1>Command 实例</h1>
|
||||
<p><code>command</code>实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过<code>mindMap.command</code>获取到该实例</p>
|
||||
<h2>属性</h2>
|
||||
<h3>history</h3>
|
||||
<p>当前所有的历史数据列表。不要手动修改该数组。</p>
|
||||
<h3>activeHistoryIndex</h3>
|
||||
<p>当前所在的历史数据索引。不要手动修改该属性。</p>
|
||||
<h2>方法</h2>
|
||||
<p>前进后退请使用命令<code>BACK</code>或<code>FORWARD</code>。</p>
|
||||
<h3>pause()</h3>
|
||||
<blockquote>
|
||||
<p>v0.9.11+</p>
|
||||
@@ -22,7 +28,7 @@
|
||||
<p><code>name</code>:要移除的命令名称</p>
|
||||
<p><code>fn</code>:要移除的方法,不传的话移除该命令所有的方法</p>
|
||||
<h3>getCopyData()</h3>
|
||||
<p>获取渲染树数据副本</p>
|
||||
<p>获取渲染树数据副本。即当前画布的数据。</p>
|
||||
<h3>clearHistory()</h3>
|
||||
<p>清空历史堆栈数据</p>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const mindMap = new MindMap({
|
||||
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ |
|
||||
| el | Element | | 容器元素,必传,必须为DOM元素(当容器元素在页面上的位置发生了改变,但大小没有改变的情况下必须调用`getElRectInfo()`方法更新库内部的相关信息;当大小也发生了改变后必须调用`resize()`方法,否则会造成一些功能异常) |
|
||||
| data | Object 、 null | | 思维导图数据,可参考下方【数据结构】介绍。v0.9.9+支持传空对象或者null,画布会显示空白 |
|
||||
| layout | String | logicalStructure | 布局类型,可选列表:logicalStructure(逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图)、timeline(v0.5.4+,时间轴)、timeline2(v0.5.4+,上下交替型时间轴)、fishbone(v0.5.4+,鱼骨图) |
|
||||
| layout | String | logicalStructure | 布局类型,可选列表:logicalStructure(逻辑结构图)、logicalStructureLeft(v0.10.2+,向左逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图)、timeline(v0.5.4+,时间轴)、timeline2(v0.5.4+,上下交替型时间轴)、fishbone(v0.5.4+,鱼骨图) |
|
||||
| fishboneDeg(v0.5.4+) | Number | 45 | 设置鱼骨结构图的斜线角度 |
|
||||
| theme | String | default | 主题,可选列表:default(默认)、classic(脑图经典)、minions(小黄人)、pinkGrape(粉红葡萄)、mint(薄荷)、gold(金色vip)、vitalityOrange(活力橙)、greenLeaf(绿叶)、dark2(暗色2)、skyGreen(天清绿)、classic2(脑图经典2)、classic3(脑图经典3)、classic4(脑图经典4,v0.2.0+)、classicGreen(经典绿)、classicBlue(经典蓝)、blueSky(天空蓝)、brainImpairedPink(脑残粉)、dark(暗色)、earthYellow(泥土黄)、freshGreen(清新绿)、freshRed(清新红)、romanticPurple(浪漫紫)、simpleBlack(v0.5.4+简约黑)、courseGreen(v0.5.4+课程绿)、coffee(v0.5.4+咖啡)、redSpirit(v0.5.4+红色精神)、blackHumour(v0.5.4+黑色幽默)、lateNightOffice(v0.5.4+深夜办公室)、blackGold(v0.5.4+黑金)、avocado(v.5.10-fix.2+牛油果)、autumn(v.5.10-fix.2+秋天)、orangeJuice(v.5.10-fix.2+橙汁) |
|
||||
| themeConfig | Object | {} | 主题配置,会和所选择的主题进行合并,可用字段可参考:[default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) |
|
||||
@@ -96,6 +96,8 @@ const mindMap = new MindMap({
|
||||
| resetScaleOnMoveNodeToCenter(v0.9.12+) | Boolean | false | 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%(该选项实际影响的是render.moveNodeToCenter方法,moveNodeToCenter方法本身也存在第二个参数resetScale来设置是否复位,如果resetScale参数没有传递,那么使用resetScaleOnMoveNodeToCenter配置,否则使用resetScale配置)。 |
|
||||
| createNodePrefixContent(v0.9.12+) | Function、null | null | 添加附加的节点前置内容。前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。可以传递一个函数,这个函数接收一个节点实例的参数,可以返回{el, width, height}格式的对象,el为DOM节点对象,width和height代表内容的宽高,数字类型,如果不需要自定义内容,也可以返回null |
|
||||
| createNodePostfixContent(v0.9.12+) | Function、null | null | 添加附加的节点后置内容。后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分。用法同createNodePrefixContent |
|
||||
| disabledClipboard(v0.10.2+) | Boolean | false | 是否禁止粘贴用户剪贴板中的数据,禁止将复制的节点数据写入用户的剪贴板中,此时只能复制和粘贴画布内的节点数据 |
|
||||
| customHyperlinkJump(v0.10.2+) | null、Function | false | 自定义超链接的跳转。如果不传,默认会以新窗口的方式打开超链接,可以传递一个函数,函数接收两个参数:link(超链接的url)、node(所属节点实例),只要传递了函数,就会阻止默认的跳转 |
|
||||
|
||||
#### 1.1数据结构
|
||||
|
||||
@@ -217,8 +219,9 @@ new MindMap({
|
||||
| dragPlaceholderRectFill(v0.7.2+) | String | rgb(94, 200, 248) | 节点拖拽时新位置的示意矩形的填充颜色 |
|
||||
| dragPlaceholderLineConfig(v0.10.0+) | Object | { color: 'rgb(94, 200, 248)', width: 2 } | 节点拖拽时新位置的示意连线的样式配置 |
|
||||
| dragOpacityConfig(v0.7.2+) | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | 节点拖拽时的透明度配置,传递一个对象,字段含义分别为:跟随鼠标移动的克隆节点或矩形的透明度、被拖拽节点的透明度 |
|
||||
| beforeDragEnd(v0.10.1+) | null、Function | null | 即将拖拽完成前调用该函数,函数接收一个对象作为参数:{overlapNodeUid,prevNodeUid,nextNodeUid},代表拖拽信息,如果要阻止本次拖拽,那么可以返回true,此时node_dragend事件不会再触发。函数可以是异步函数,返回Promise实例 |
|
||||
| beforeDragEnd(v0.10.1+) | null、Function | null | 即将拖拽完成前调用该函数,函数接收一个对象作为参数:{overlapNodeUid,prevNodeUid,nextNodeUid,beingDragNodeList},代表拖拽信息,如果要阻止本次拖拽,那么可以返回true,此时node_dragend事件不会再触发。函数可以是异步函数,返回Promise实例。beingDragNodeList为v0.10.2+新增的回调参数,为当前被拖拽的节点列表 |
|
||||
| handleDragCloneNode(v0.10.1+) | null、Function | null | 拖拽单个节点时会克隆被拖拽节点,如果想修改该克隆节点,那么可以通过该选项提供一个处理函数,函数接收克隆节点对象。(需要注意的是节点对象指的是@svgdotjs/svg.js库的元素对象,所以你需要阅读该库的文档来操作该对象) |
|
||||
| beforeDragStart(v0.10.2+) | null、Function((nodeList) => {}) | null | 即将开始拖拽节点前调用该函数,函数接收当前即将被拖拽的节点实例列表作为参数,如果要阻止本次拖拽,那么可以返回true。可以是异步函数,返回一个Promise实例 |
|
||||
|
||||
### 5.Watermark插件
|
||||
|
||||
@@ -550,7 +553,7 @@ mindMap.setTheme('主题名称')
|
||||
| node_active | 节点激活事件 | this(节点实例)、activeNodeList(当前激活的所有节点列表) |
|
||||
| expand_btn_click | 节点展开或收缩事件 | this(节点实例) |
|
||||
| before_show_text_edit | 节点文本编辑框即将打开事件 | |
|
||||
| hide_text_edit | 节点文本编辑框关闭事件 | textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表) |
|
||||
| hide_text_edit | 节点文本编辑框关闭事件【关联线的文本编辑结束也会触发该事件,此时没有回调参数,所以需要做好防御性编程】 | textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表)、node(v0.10.2+,当前文本编辑的节点实例) |
|
||||
| scale | 画布放大缩小事件 | scale(缩放比例) |
|
||||
| translate(v0.9.10+) | 画布移动事件 | x(水平位移)、y(垂直位移) |
|
||||
| node_img_dblclick(v0.2.15+) | 节点内图片的双击事件 | this(节点实例)、e(事件对象) |
|
||||
@@ -584,6 +587,8 @@ mindMap.setTheme('主题名称')
|
||||
| demonstrate_jump(v0.9.11+) | 演示模式中,切换步骤时触发 | currentStepIndex(当前播放到的步骤索引,从0开始计数)、stepLength(总的播放步骤数量) |
|
||||
| node_tag_click(v0.9.12+) | 节点标签的点击事件 | this(当前节点实例)、item(点击的标签内容) |
|
||||
| node_layout_end(v0.10.1+) | 单个节点内容布局完成的事件 | this(当前节点实例) |
|
||||
| node_attachmentClick(v0.9.10+) | 节点附件图标的点击事件 | this(当前节点实例)、e(事件对象)、node(图标节点) |
|
||||
| node_attachmentContextmenu(v0.9.10+) | 节点附件图标的右键点击事件 | this(当前节点实例)、e(事件对象)、node(图标节点) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<td>layout</td>
|
||||
<td>String</td>
|
||||
<td>logicalStructure</td>
|
||||
<td>布局类型,可选列表:logicalStructure(逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图)、timeline(v0.5.4+,时间轴)、timeline2(v0.5.4+,上下交替型时间轴)、fishbone(v0.5.4+,鱼骨图)</td>
|
||||
<td>布局类型,可选列表:logicalStructure(逻辑结构图)、logicalStructureLeft(v0.10.2+,向左逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图)、timeline(v0.5.4+,时间轴)、timeline2(v0.5.4+,上下交替型时间轴)、fishbone(v0.5.4+,鱼骨图)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>fishboneDeg(v0.5.4+)</td>
|
||||
@@ -448,6 +448,18 @@
|
||||
<td>null</td>
|
||||
<td>添加附加的节点后置内容。后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分。用法同createNodePrefixContent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>disabledClipboard(v0.10.2+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>是否禁止粘贴用户剪贴板中的数据,禁止将复制的节点数据写入用户的剪贴板中,此时只能复制和粘贴画布内的节点数据</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customHyperlinkJump(v0.10.2+)</td>
|
||||
<td>null、Function</td>
|
||||
<td>false</td>
|
||||
<td>自定义超链接的跳转。如果不传,默认会以新窗口的方式打开超链接,可以传递一个函数,函数接收两个参数:link(超链接的url)、node(所属节点实例),只要传递了函数,就会阻止默认的跳转</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h4>1.1数据结构</h4>
|
||||
@@ -692,7 +704,7 @@
|
||||
<td>beforeDragEnd(v0.10.1+)</td>
|
||||
<td>null、Function</td>
|
||||
<td>null</td>
|
||||
<td>即将拖拽完成前调用该函数,函数接收一个对象作为参数:{overlapNodeUid,prevNodeUid,nextNodeUid},代表拖拽信息,如果要阻止本次拖拽,那么可以返回true,此时node_dragend事件不会再触发。函数可以是异步函数,返回Promise实例</td>
|
||||
<td>即将拖拽完成前调用该函数,函数接收一个对象作为参数:{overlapNodeUid,prevNodeUid,nextNodeUid,beingDragNodeList},代表拖拽信息,如果要阻止本次拖拽,那么可以返回true,此时node_dragend事件不会再触发。函数可以是异步函数,返回Promise实例。beingDragNodeList为v0.10.2+新增的回调参数,为当前被拖拽的节点列表</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>handleDragCloneNode(v0.10.1+)</td>
|
||||
@@ -700,6 +712,12 @@
|
||||
<td>null</td>
|
||||
<td>拖拽单个节点时会克隆被拖拽节点,如果想修改该克隆节点,那么可以通过该选项提供一个处理函数,函数接收克隆节点对象。(需要注意的是节点对象指的是@svgdotjs/svg.js库的元素对象,所以你需要阅读该库的文档来操作该对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>beforeDragStart(v0.10.2+)</td>
|
||||
<td>null、Function((nodeList) => {})</td>
|
||||
<td>null</td>
|
||||
<td>即将开始拖拽节点前调用该函数,函数接收当前即将被拖拽的节点实例列表作为参数,如果要阻止本次拖拽,那么可以返回true。可以是异步函数,返回一个Promise实例</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>5.Watermark插件</h3>
|
||||
@@ -1307,8 +1325,8 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hide_text_edit</td>
|
||||
<td>节点文本编辑框关闭事件</td>
|
||||
<td>textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表)</td>
|
||||
<td>节点文本编辑框关闭事件【关联线的文本编辑结束也会触发该事件,此时没有回调参数,所以需要做好防御性编程】</td>
|
||||
<td>textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表)、node(v0.10.2+,当前文本编辑的节点实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scale</td>
|
||||
@@ -1475,6 +1493,16 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<td>单个节点内容布局完成的事件</td>
|
||||
<td>this(当前节点实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_attachmentClick(v0.9.10+)</td>
|
||||
<td>节点附件图标的点击事件</td>
|
||||
<td>this(当前节点实例)、e(事件对象)、node(图标节点)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_attachmentContextmenu(v0.9.10+)</td>
|
||||
<td>节点附件图标的右键点击事件</td>
|
||||
<td>this(当前节点实例)、e(事件对象)、node(图标节点)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
|
||||
@@ -52,7 +52,7 @@ miniMapContainer.innerHTML = svgHTML
|
||||
|
||||
到这一步,当画布上的思维导图变化了,小地图也会实时更新,并且视口框元素会实时反映视口在思维导图图形上的位置
|
||||
|
||||
6.监听container元素的mousedown、mousemove、mouseup事件,分别调用小地图插件实例的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果
|
||||
6.监听container元素的mousedown、mousemove事件,并且监听window的mouseup事件(如果将mouseup绑定到container元素上,那么鼠标移出container元素整个拖拽行为无法停止),分别调用小地图插件实例的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果
|
||||
|
||||
插件的完整信息可以参考[miniMap](https://wanglin2.github.io/mind-map/#/doc/zh/miniMap)。
|
||||
|
||||
@@ -64,6 +64,30 @@ getImgUrl(img => {
|
||||
})
|
||||
```
|
||||
|
||||
在`v0.10.2+`版本之后,支持拖拽小地图内的视口框元素来同步移动画布位置,也就是可以拖拽`viewBoxContainer`元素,要实现这个特性,需要监听`viewBoxContainer`元素的`mousedown`(需要阻止冒泡,否则会触发container元素的mousedown事件)、`mousemove`事件,分别调用小地图插件实例的方法:
|
||||
|
||||
```js
|
||||
// mousedown事件调用
|
||||
mindMap.miniMap.onViewBoxMousedown(e)
|
||||
// mousemove事件调用
|
||||
mindMap.miniMap.onViewBoxMousemove(e)
|
||||
```
|
||||
|
||||
同时需要监听`mini_map_view_box_position_change`事件来实时更新`viewBoxContainer`元素:
|
||||
|
||||
```js
|
||||
mindMap.on('mini_map_view_box_position_change', ({ left, right, top, bottom }) => {
|
||||
viewBoxStyle.left = left
|
||||
viewBoxStyle.right = right
|
||||
viewBoxStyle.top = top
|
||||
viewBoxStyle.bottom = bottom
|
||||
})
|
||||
```
|
||||
|
||||
需要注意,如果你给`viewBoxContainer`元素设置了`css`的`transition`属性来增加过渡效果,那么在`mini_map_view_box_position_change`事件里需要临时去除,否则拖动会不流畅,可以在前面的`mouseup`事件里恢复。
|
||||
|
||||
## 完整示例
|
||||
|
||||
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVt2O20QUfpWRASULWSfbUgQhW5UCEkgNQqUSF0yVeu1J4sqesTzjJFWUm4oLhEBcIH6LBFyBhBStEBdsJXgaki1vwTn2jD12stpy1ZU28sz3nZ85c35m6byRJO4sY07fGUg/DRNFJFNZcp3yME5EqsiSpGzcIYIPRcYVCzpETr0oEvPbbExWZJyKmLRAQ6uUGIY8GHpJAVFHwnbEDmPYPYy9hDqUE0J5xBTBPWQeE55FEeWUd7tkc/rF5ofTzaO/N+uzzXe/nn//8Wb917+/fUu5L7hUBH6VF3KWfhgGagqyR73eDvYOCydTBeA1wHK120d/bL8+LZUbCXAhBBfeNIIgAudtoz8HhjML2fymWHygHkRM48tViWoNSPC9knC0B7/FxugSwr098B2BkaijWRJ4ikFEwyGC7QNyfJ0sMYJwpCfrn8/X35RH2n51uv18jRjGFuQ8kNAhdrUZF1z0s8hTIVxosdWuB7TTDCL4klvb/vn79scvN5/YMSQ78XNnXpQxN+Qof2d4C1xAT1w5m+ASRexwFnRDshFLuQltndwA63wM9UV0xOpsiPxFZIAoX2EOFReS14FkgZhzvA9WXUgz0hYTaPuUxGKGFp9CCTIvUJLleXG5iiypFJTF3LYSyipGNjdF3M4hQljUJ4Hws5hx5U6Yejti+HnzwbtBu6UlyxxoHXQKKYxlv9COf9TBDepYW8W2YguF29TZ/nT25NOH5w/PijaBfyutDIn+NIyClHEkf1TpaKjba6Vp6Z/Hn50//qVprG5wj9G7FWbznpEH5lPvGTm4eXVbCPWeCNj7QoZY7SDZiiDzWx3S8uHq4Jru5vTVwetFR65SR/B2C48w8qcenzAQsftQ3hBsKpbt6H/wObg1UiljIzhTwNIR/O7KYIcddIuhBOMIForBJAEKrAgZBOGM+JEn5TF1tPa3oFCok8OaEAYVWuYnUAZdQG2iiaTRWDbB6mZuxKaeAbeq2zCoKhhYrBUDV01GllR4piciIdodqmoOWT41ey11bBYMjr0ci9KX2FmB1chLlXpcjkUa98k9ic20/fyy0V5XB/dqSYlDZqz6zen2Emkli1aDqURiE3HOFbyysBVVq8pTHYgc0V/2fTXuXg8NOyrlOWsDpXHr5bf5GnStBINlriRn3NAvG+q43eI5o9ujy2Ts+lJSp6wh7LsmF039z3Gw9vGh8kLOIyQpqzJlOI1nLAfygsb/55o5a1RVgt6JFFGmCkFzHT29ykNuFrvmp/lk75OXe71kYSzvt/uisRx76SQEu0Zr4gVByCdmo3TdLUvnKX0+Mj5ot6115Xm5ZVy/ZnleRb7+lrvMfpn3hyIN88OhR+hFQ3Mzxy7VfCJSaGx9ciVZEADCgKSTk/aVq692yCuv4X/RdLULRkcUkZ57VRrj0P3yFHQ6TpGA+H5270vB4bmee0A1AAlYDhvI+gySHSeM24VPN4VRH8YMc/XwJBVzCa+0+yChq3TPC72Q3c10lNK+rZzVf9RSHZw=" />
|
||||
在线Demo小地图代码:[Navigator.vue](https://github.com/wanglin2/mind-map/blob/main/web/src/pages/Edit/components/Navigator.vue)。
|
||||
|
||||
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFV1tvG0UU/iujBWQHnLXbUgQmqUpLJZAShEoED2zlbrxje6v1zmp3bKeyLEGFArSp8sCt0EqkApFKSFGEEGrShl/jS/LEX+Cc2Znd2bXdhCcs2d6Z853LnDm37RvvBIHZ7VCjaixF9dANOIko7wSXLN9tByzkpE9C2igR5q+yjs+pUyJRy/Y81rtOG2RAGiFrkwJIKCQcq67vrNpBTLKMCLY9utiG3cW2HViG5RNi+R7lBPcQuUz8judZvuWXy2S0vz16tD96+Pdo72D045PJT1+M9o5Ofn9g+XXmR5zAL7ddn4afuA5vAe+5SmWK9h51my0OxItAE2LHD/8cf7+fCFccYIILJlxVjMAC5y2iPQsK03Vp7wrb+Ijf9qik9wcJtefy1lpo+5HLXeZLOg87NEFIHSiibicizs2gr9AGGo3kygzyGkNfZamdwLE5BZ+7q0gsLpDlS6SPPoZDH+89nuz9kBx6/N3++P4e0tD7wGcDh7wEU6oxwcR6x7PxMEKqHRSzLi/l3Qy2CG3jp3+Mf/5m9JXuZTLlYbNrex1quj7yr62ugAloiRl1m7hEFt3hMVyBdIomXLk2C84Rs3h09Tw40rJo8Pw8MJAsf4BRFl+IyJSIOqyHwVCk6YXkPa0hATZLSJt1UeMZhCByjpCOiAtNRDZik3NhzL5AQydI5WNo7W6Otn8ZP96EBD15vjPe+XK89fXw6b3h4b3hs79SEz6Ob+zsPskzKK0zdU52n43uPnmRzjO5MM8w96TDo/uTo73Rr7sQ4uNvD0bbD4aHm/883zp59Nnxb5/HNWbKjg9Z7OmrLdtvCmP6kIANXiIhpk+JcBaUyDrjHArm4NR7atheJC5qOk1MFAsQ/JuDECqxiuD/HAzYg/GAgT2TLk1dljZLVyUtoqgVIa3E055qDUVBIoR6VeKweqdNfW42Kb/mUXy8cvt9p1iQnEndKCyUYi7Mv2osHT+WgRuWoW3F25xucNy2jPHOwfHdO5M7B3Hzwc9ACkNgveV6Tkh9BH+aysiJm6klr2l4uDU53M0ryyqcofRGStNx/5MF6lHuKT7IFn6dMf4Bc6gKaeAsYLAVSqRQh6uDa7oh4IOFt+M+n6Yb84sFPEKtLvIAWPTeJZqIDsW4q/0HvA9m1XhIaQ3O5NCwBr+zeHrAw3qm7TjXumDxihtxCuEFARdXOeBJKt6UEiwZNZhiasK6dbZRC6QnUivn5D1WFPguleM5CyYsWHAKwxHYBytClhy3S+qeHUXLliG1vgv1yDIEWQJcJ6UmyQGQpTJQdaC6RiUx6dppWFwWZ8YqC3StHSmExWME1sQUgSuFkAotnlGpac23f8vQUTDLzMRokGqElQdQubDnWBkbLGxXyc0I+3vx5X6u4w8WbmZiHueeBq/mB67XSCHYKOSQUP10II5eMS6pG9zig9RS6QhBkU/6jeTuRPeQLLBzPJSePzP75DBKVj/XNKr58VSzOBsAZgQnFnecb8ApBx45FxD5zqmJz0Zk8qyelspa8MNSHFMgLssXCcswy/Hbg+wbJo3aZj2KLCMpLtjEVZ6owtjDKbWK7wWvCBwhKkmrEHA42napIIhKh9+X8vmkRKWM9nrEvA6PGVUgVeRKBItaTKtviTG5Sl6vVIINpXm23leV5rYdNl3Qq6QGULBcv6k2EtPNJK3PaPM5ZYM0W1unlidbyvSLmuWp57OvTqfpTzJ2kcH0gYcT4wpYkZOcz4hTJa+zECp+lZwPNggQXIeEzfXi+Qtvlsgbb+E37kbSBCXD80jFvBCdotzMZVBShubKEtKgzouANkpGHM748mveipgP79pChiUJEM5JT4cshyFcNHKzDI9mCBOV26YY+YvrIetFYNAt4JDVasbrdcw7nTfIJU86MAb/Ak6Okok=" />
|
||||
@@ -35,15 +35,31 @@
|
||||
</code></pre>
|
||||
<p>5.将viewBoxStyle对象设置为viewBoxContainer元素的样式</p>
|
||||
<p>到这一步,当画布上的思维导图变化了,小地图也会实时更新,并且视口框元素会实时反映视口在思维导图图形上的位置</p>
|
||||
<p>6.监听container元素的mousedown、mousemove、mouseup事件,分别调用小地图插件实例的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果</p>
|
||||
<p>6.监听container元素的mousedown、mousemove事件,并且监听window的mouseup事件(如果将mouseup绑定到container元素上,那么鼠标移出container元素整个拖拽行为无法停止),分别调用小地图插件实例的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果</p>
|
||||
<p>插件的完整信息可以参考<a href="https://wanglin2.github.io/mind-map/#/doc/zh/miniMap">miniMap</a>。</p>
|
||||
<p>在<code>v0.8.0+</code>版本之后,<code>calculationMiniMap</code>方法会返回<code>getImgUrl</code>属性,这是一个异步函数,你可以调用它并传递一个回调函数,回调函数可以接收一个参数,代表小地图图片数据,然后可以通过<code>img</code>标签进行渲染,替代前面的<code>svgHTML</code>,这样可以减少页面上的节点数量,能优化一定的性能:</p>
|
||||
<pre class="hljs"><code>getImgUrl(<span class="hljs-function"><span class="hljs-params">img</span> =></span> {
|
||||
img.src = img
|
||||
})
|
||||
</code></pre>
|
||||
<p>在<code>v0.10.2+</code>版本之后,支持拖拽小地图内的视口框元素来同步移动画布位置,也就是可以拖拽<code>viewBoxContainer</code>元素,要实现这个特性,需要监听<code>viewBoxContainer</code>元素的<code>mousedown</code>(需要阻止冒泡,否则会触发container元素的mousedown事件)、<code>mousemove</code>事件,分别调用小地图插件实例的方法:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// mousedown事件调用</span>
|
||||
mindMap.miniMap.onViewBoxMousedown(e)
|
||||
<span class="hljs-comment">// mousemove事件调用</span>
|
||||
mindMap.miniMap.onViewBoxMousemove(e)
|
||||
</code></pre>
|
||||
<p>同时需要监听<code>mini_map_view_box_position_change</code>事件来实时更新<code>viewBoxContainer</code>元素:</p>
|
||||
<pre class="hljs"><code>mindMap.on(<span class="hljs-string">'mini_map_view_box_position_change'</span>, <span class="hljs-function">(<span class="hljs-params">{ left, right, top, bottom }</span>) =></span> {
|
||||
viewBoxStyle.left = left
|
||||
viewBoxStyle.right = right
|
||||
viewBoxStyle.top = top
|
||||
viewBoxStyle.bottom = bottom
|
||||
})
|
||||
</code></pre>
|
||||
<p>需要注意,如果你给<code>viewBoxContainer</code>元素设置了<code>css</code>的<code>transition</code>属性来增加过渡效果,那么在<code>mini_map_view_box_position_change</code>事件里需要临时去除,否则拖动会不流畅,可以在前面的<code>mouseup</code>事件里恢复。</p>
|
||||
<h2>完整示例</h2>
|
||||
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVt2O20QUfpWRASULWSfbUgQhW5UCEkgNQqUSF0yVeu1J4sqesTzjJFWUm4oLhEBcIH6LBFyBhBStEBdsJXgaki1vwTn2jD12stpy1ZU28sz3nZ85c35m6byRJO4sY07fGUg/DRNFJFNZcp3yME5EqsiSpGzcIYIPRcYVCzpETr0oEvPbbExWZJyKmLRAQ6uUGIY8GHpJAVFHwnbEDmPYPYy9hDqUE0J5xBTBPWQeE55FEeWUd7tkc/rF5ofTzaO/N+uzzXe/nn//8Wb917+/fUu5L7hUBH6VF3KWfhgGagqyR73eDvYOCydTBeA1wHK120d/bL8+LZUbCXAhBBfeNIIgAudtoz8HhjML2fymWHygHkRM48tViWoNSPC9knC0B7/FxugSwr098B2BkaijWRJ4ikFEwyGC7QNyfJ0sMYJwpCfrn8/X35RH2n51uv18jRjGFuQ8kNAhdrUZF1z0s8hTIVxosdWuB7TTDCL4klvb/vn79scvN5/YMSQ78XNnXpQxN+Qof2d4C1xAT1w5m+ASRexwFnRDshFLuQltndwA63wM9UV0xOpsiPxFZIAoX2EOFReS14FkgZhzvA9WXUgz0hYTaPuUxGKGFp9CCTIvUJLleXG5iiypFJTF3LYSyipGNjdF3M4hQljUJ4Hws5hx5U6Yejti+HnzwbtBu6UlyxxoHXQKKYxlv9COf9TBDepYW8W2YguF29TZ/nT25NOH5w/PijaBfyutDIn+NIyClHEkf1TpaKjba6Vp6Z/Hn50//qVprG5wj9G7FWbznpEH5lPvGTm4eXVbCPWeCNj7QoZY7SDZiiDzWx3S8uHq4Jru5vTVwetFR65SR/B2C48w8qcenzAQsftQ3hBsKpbt6H/wObg1UiljIzhTwNIR/O7KYIcddIuhBOMIForBJAEKrAgZBOGM+JEn5TF1tPa3oFCok8OaEAYVWuYnUAZdQG2iiaTRWDbB6mZuxKaeAbeq2zCoKhhYrBUDV01GllR4piciIdodqmoOWT41ey11bBYMjr0ci9KX2FmB1chLlXpcjkUa98k9ic20/fyy0V5XB/dqSYlDZqz6zen2Emkli1aDqURiE3HOFbyysBVVq8pTHYgc0V/2fTXuXg8NOyrlOWsDpXHr5bf5GnStBINlriRn3NAvG+q43eI5o9ujy2Ts+lJSp6wh7LsmF039z3Gw9vGh8kLOIyQpqzJlOI1nLAfygsb/55o5a1RVgt6JFFGmCkFzHT29ykNuFrvmp/lk75OXe71kYSzvt/uisRx76SQEu0Zr4gVByCdmo3TdLUvnKX0+Mj5ot6115Xm5ZVy/ZnleRb7+lrvMfpn3hyIN88OhR+hFQ3Mzxy7VfCJSaGx9ciVZEADCgKSTk/aVq692yCuv4X/RdLULRkcUkZ57VRrj0P3yFHQ6TpGA+H5270vB4bmee0A1AAlYDhvI+gySHSeM24VPN4VRH8YMc/XwJBVzCa+0+yChq3TPC72Q3c10lNK+rZzVf9RSHZw=" />
|
||||
<p>在线Demo小地图代码:<a href="https://github.com/wanglin2/mind-map/blob/main/web/src/pages/Edit/components/Navigator.vue">Navigator.vue</a>。</p>
|
||||
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFV1tvG0UU/iujBWQHnLXbUgQmqUpLJZAShEoED2zlbrxje6v1zmp3bKeyLEGFArSp8sCt0EqkApFKSFGEEGrShl/jS/LEX+Cc2Znd2bXdhCcs2d6Z853LnDm37RvvBIHZ7VCjaixF9dANOIko7wSXLN9tByzkpE9C2igR5q+yjs+pUyJRy/Y81rtOG2RAGiFrkwJIKCQcq67vrNpBTLKMCLY9utiG3cW2HViG5RNi+R7lBPcQuUz8judZvuWXy2S0vz16tD96+Pdo72D045PJT1+M9o5Ofn9g+XXmR5zAL7ddn4afuA5vAe+5SmWK9h51my0OxItAE2LHD/8cf7+fCFccYIILJlxVjMAC5y2iPQsK03Vp7wrb+Ijf9qik9wcJtefy1lpo+5HLXeZLOg87NEFIHSiibicizs2gr9AGGo3kygzyGkNfZamdwLE5BZ+7q0gsLpDlS6SPPoZDH+89nuz9kBx6/N3++P4e0tD7wGcDh7wEU6oxwcR6x7PxMEKqHRSzLi/l3Qy2CG3jp3+Mf/5m9JXuZTLlYbNrex1quj7yr62ugAloiRl1m7hEFt3hMVyBdIomXLk2C84Rs3h09Tw40rJo8Pw8MJAsf4BRFl+IyJSIOqyHwVCk6YXkPa0hATZLSJt1UeMZhCByjpCOiAtNRDZik3NhzL5AQydI5WNo7W6Otn8ZP96EBD15vjPe+XK89fXw6b3h4b3hs79SEz6Ob+zsPskzKK0zdU52n43uPnmRzjO5MM8w96TDo/uTo73Rr7sQ4uNvD0bbD4aHm/883zp59Nnxb5/HNWbKjg9Z7OmrLdtvCmP6kIANXiIhpk+JcBaUyDrjHArm4NR7atheJC5qOk1MFAsQ/JuDECqxiuD/HAzYg/GAgT2TLk1dljZLVyUtoqgVIa3E055qDUVBIoR6VeKweqdNfW42Kb/mUXy8cvt9p1iQnEndKCyUYi7Mv2osHT+WgRuWoW3F25xucNy2jPHOwfHdO5M7B3Hzwc9ACkNgveV6Tkh9BH+aysiJm6klr2l4uDU53M0ryyqcofRGStNx/5MF6lHuKT7IFn6dMf4Bc6gKaeAsYLAVSqRQh6uDa7oh4IOFt+M+n6Yb84sFPEKtLvIAWPTeJZqIDsW4q/0HvA9m1XhIaQ3O5NCwBr+zeHrAw3qm7TjXumDxihtxCuEFARdXOeBJKt6UEiwZNZhiasK6dbZRC6QnUivn5D1WFPguleM5CyYsWHAKwxHYBytClhy3S+qeHUXLliG1vgv1yDIEWQJcJ6UmyQGQpTJQdaC6RiUx6dppWFwWZ8YqC3StHSmExWME1sQUgSuFkAotnlGpac23f8vQUTDLzMRokGqElQdQubDnWBkbLGxXyc0I+3vx5X6u4w8WbmZiHueeBq/mB67XSCHYKOSQUP10II5eMS6pG9zig9RS6QhBkU/6jeTuRPeQLLBzPJSePzP75DBKVj/XNKr58VSzOBsAZgQnFnecb8ApBx45FxD5zqmJz0Zk8qyelspa8MNSHFMgLssXCcswy/Hbg+wbJo3aZj2KLCMpLtjEVZ6owtjDKbWK7wWvCBwhKkmrEHA42napIIhKh9+X8vmkRKWM9nrEvA6PGVUgVeRKBItaTKtviTG5Sl6vVIINpXm23leV5rYdNl3Qq6QGULBcv6k2EtPNJK3PaPM5ZYM0W1unlidbyvSLmuWp57OvTqfpTzJ2kcH0gYcT4wpYkZOcz4hTJa+zECp+lZwPNggQXIeEzfXi+Qtvlsgbb+E37kbSBCXD80jFvBCdotzMZVBShubKEtKgzouANkpGHM748mveipgP79pChiUJEM5JT4cshyFcNHKzDI9mCBOV26YY+YvrIetFYNAt4JDVasbrdcw7nTfIJU86MAb/Ak6Okok=" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## 特性
|
||||
|
||||
- [x] 插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积
|
||||
- [x] 支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构
|
||||
- [x] 支持逻辑结构图(向左、向右逻辑结构图)、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构
|
||||
- [x] 内置多种主题,允许高度自定义样式,支持注册新主题
|
||||
- [x] 节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式
|
||||
- [x] 节点支持拖拽(拖拽移动、自由调整)、多种节点形状;支持扩展节点内容、支持使用 DDM 完全自定义节点内容
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
官方提供了如下插件,可根据需求按需引入(某个功能不生效大概率是因为你没有引入对应的插件),具体使用方式请查看文档:
|
||||
|
||||
> RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]
|
||||
> RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、OuterFrame(外框插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]
|
||||
|
||||
本项目不会实现的特性:
|
||||
|
||||
@@ -424,4 +424,16 @@
|
||||
<img src="../../../../assets/avatar/Kyle.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>Kyle</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/lsytyrt.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>lsytyrt</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/秀树因馨雨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>秀树因馨雨</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/buddy.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>buddy</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,22 +8,22 @@
|
||||
</blockquote>
|
||||
<h2>特性</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox51" checked="true" /><label for="checkbox51">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox52" checked="true" /><label for="checkbox52">支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox53" checked="true" /><label for="checkbox53">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox54" checked="true" /><label for="checkbox54">节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式</label></li>
|
||||
<li><input type="checkbox" id="checkbox55" checked="true" /><label for="checkbox55">节点支持拖拽(拖拽移动、自由调整)、多种节点形状;支持扩展节点内容、支持使用 DDM 完全自定义节点内容</label></li>
|
||||
<li><input type="checkbox" id="checkbox56" checked="true" /><label for="checkbox56">支持画布拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox57" checked="true" /><label for="checkbox57">支持鼠标按键拖动选择和 Ctrl+左键两种多选节点方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox58" checked="true" /><label for="checkbox58">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>、<code>txt</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox59" checked="true" /><label for="checkbox59">支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条、手绘风格、彩虹线条</label></li>
|
||||
<li><input type="checkbox" id="checkbox60" checked="true" /><label for="checkbox60">提供丰富的配置,满足各种场景各种使用习惯</label></li>
|
||||
<li><input type="checkbox" id="checkbox61" checked="true" /><label for="checkbox61">支持协同编辑</label></li>
|
||||
<li><input type="checkbox" id="checkbox62" checked="true" /><label for="checkbox62">支持演示模式</label></li>
|
||||
<li><input type="checkbox" id="checkbox34" checked="true" /><label for="checkbox34">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox35" checked="true" /><label for="checkbox35">支持逻辑结构图(向左、向右逻辑结构图)、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox36" checked="true" /><label for="checkbox36">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox37" checked="true" /><label for="checkbox37">节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式</label></li>
|
||||
<li><input type="checkbox" id="checkbox38" checked="true" /><label for="checkbox38">节点支持拖拽(拖拽移动、自由调整)、多种节点形状;支持扩展节点内容、支持使用 DDM 完全自定义节点内容</label></li>
|
||||
<li><input type="checkbox" id="checkbox39" checked="true" /><label for="checkbox39">支持画布拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox40" checked="true" /><label for="checkbox40">支持鼠标按键拖动选择和 Ctrl+左键两种多选节点方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox41" checked="true" /><label for="checkbox41">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>、<code>txt</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox42" checked="true" /><label for="checkbox42">支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条、手绘风格、彩虹线条</label></li>
|
||||
<li><input type="checkbox" id="checkbox43" checked="true" /><label for="checkbox43">提供丰富的配置,满足各种场景各种使用习惯</label></li>
|
||||
<li><input type="checkbox" id="checkbox44" checked="true" /><label for="checkbox44">支持协同编辑</label></li>
|
||||
<li><input type="checkbox" id="checkbox45" checked="true" /><label for="checkbox45">支持演示模式</label></li>
|
||||
</ul>
|
||||
<p>官方提供了如下插件,可根据需求按需引入(某个功能不生效大概率是因为你没有引入对应的插件),具体使用方式请查看文档:</p>
|
||||
<blockquote>
|
||||
<p>RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]</p>
|
||||
<p>RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、OuterFrame(外框插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]</p>
|
||||
</blockquote>
|
||||
<p>本项目不会实现的特性:</p>
|
||||
<blockquote>
|
||||
@@ -37,11 +37,11 @@
|
||||
<p>2.<code>web</code></p>
|
||||
<p>使用<code>simple-mind-map</code>库,基于<code>vue2.x</code>、<code>ElementUI</code>搭建的在线思维导图。特性:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox63" checked="true" /><label for="checkbox63">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox64" checked="true" /><label for="checkbox64">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox65" checked="true" /><label for="checkbox65">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox66" checked="true" /><label for="checkbox66">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox67" checked="true" /><label for="checkbox67">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
<li><input type="checkbox" id="checkbox46" checked="true" /><label for="checkbox46">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox47" checked="true" /><label for="checkbox47">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox48" checked="true" /><label for="checkbox48">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox49" checked="true" /><label for="checkbox49">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox50" checked="true" /><label for="checkbox50">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
</ul>
|
||||
<p>提供文档页面服务。</p>
|
||||
<p>3.<code>dist</code></p>
|
||||
@@ -375,6 +375,18 @@
|
||||
<img src="../../../../assets/avatar/Kyle.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>Kyle</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/lsytyrt.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>lsytyrt</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/秀树因馨雨.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>秀树因馨雨</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/buddy.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>buddy</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -70,17 +70,21 @@ MindMap.usePlugin(MiniMap)
|
||||
|
||||
到这一步,当画布上的思维导图变化了,小地图也会实时更新,并且视口框元素会实时反映视口在思维导图图形上的位置
|
||||
|
||||
6.监听`container`元素的`mousedown`、`mousemove`、`mouseup`事件,分别调用下面即将介绍的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果
|
||||
6.监听`container`元素的`mousedown`、`mousemove`事件,并且监听`window`的`mouseup`事件(如果将`mouseup`绑定到`container`元素上,那么鼠标移出`container`元素整个拖拽行为无法停止),分别调用下面即将介绍的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果
|
||||
|
||||
7.在v0.10.2+版本,支持拖拽小地图内的视口框来实现同步拖拽画布,实现该特性可以监听`viewBoxContainer`元素的`mousedown`(需要阻止冒泡,否则会触发`container`元素的`mousedown`事件)、`mousemove`事件,分别调用小地图插件实例的`onViewBoxMousedown`和`onViewBoxMousemove`方法,同时需要监听mini_map_view_box_position_change事件来实时更新viewBoxContainer元素。
|
||||
|
||||
详细教程请参考[如何渲染一个小地图](https://wanglin2.github.io/mind-map/#/doc/zh/course14)。
|
||||
|
||||
### onMousedown(e)
|
||||
|
||||
小地图鼠标按下事件执行该函数
|
||||
小地图鼠标按下事件执行该函数。
|
||||
|
||||
`e`:事件对象
|
||||
|
||||
### onMousemove(e, sensitivityNum = 5)
|
||||
|
||||
小地图鼠标移动事件执行该函数
|
||||
小地图鼠标移动事件执行该函数。
|
||||
|
||||
`e`:事件对象
|
||||
|
||||
@@ -88,4 +92,16 @@ MindMap.usePlugin(MiniMap)
|
||||
|
||||
### onMouseup()
|
||||
|
||||
小地图鼠标松开事件执行该函数
|
||||
小地图鼠标松开事件执行该函数。
|
||||
|
||||
### onViewBoxMousedown(e)
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
视口框元素鼠标按下事件调用该方法。
|
||||
|
||||
### onViewBoxMousemove(e)
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
视口框元素鼠标移动事件调用该方法。
|
||||
@@ -47,16 +47,28 @@ MindMap.usePlugin(MiniMap)
|
||||
</code></pre>
|
||||
<p>5.将<code>viewBoxStyle</code>对象设置为<code>viewBoxContainer</code>元素的样式</p>
|
||||
<p>到这一步,当画布上的思维导图变化了,小地图也会实时更新,并且视口框元素会实时反映视口在思维导图图形上的位置</p>
|
||||
<p>6.监听<code>container</code>元素的<code>mousedown</code>、<code>mousemove</code>、<code>mouseup</code>事件,分别调用下面即将介绍的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果</p>
|
||||
<p>6.监听<code>container</code>元素的<code>mousedown</code>、<code>mousemove</code>事件,并且监听<code>window</code>的<code>mouseup</code>事件(如果将<code>mouseup</code>绑定到<code>container</code>元素上,那么鼠标移出<code>container</code>元素整个拖拽行为无法停止),分别调用下面即将介绍的三个方法即可实现鼠标拖动时画布上的思维导图也随之拖动的效果</p>
|
||||
<p>7.在v0.10.2+版本,支持拖拽小地图内的视口框来实现同步拖拽画布,实现该特性可以监听<code>viewBoxContainer</code>元素的<code>mousedown</code>(需要阻止冒泡,否则会触发<code>container</code>元素的<code>mousedown</code>事件)、<code>mousemove</code>事件,分别调用小地图插件实例的<code>onViewBoxMousedown</code>和<code>onViewBoxMousemove</code>方法,同时需要监听mini_map_view_box_position_change事件来实时更新viewBoxContainer元素。</p>
|
||||
<p>详细教程请参考<a href="https://wanglin2.github.io/mind-map/#/doc/zh/course14">如何渲染一个小地图</a>。</p>
|
||||
<h3>onMousedown(e)</h3>
|
||||
<p>小地图鼠标按下事件执行该函数</p>
|
||||
<p>小地图鼠标按下事件执行该函数。</p>
|
||||
<p><code>e</code>:事件对象</p>
|
||||
<h3>onMousemove(e, sensitivityNum = 5)</h3>
|
||||
<p>小地图鼠标移动事件执行该函数</p>
|
||||
<p>小地图鼠标移动事件执行该函数。</p>
|
||||
<p><code>e</code>:事件对象</p>
|
||||
<p><code>sensitivityNum</code>:拖动灵敏度,灵敏度越大,在小地图上拖动相同距离时实际上的画布拖动距离就越大</p>
|
||||
<h3>onMouseup()</h3>
|
||||
<p>小地图鼠标松开事件执行该函数</p>
|
||||
<p>小地图鼠标松开事件执行该函数。</p>
|
||||
<h3>onViewBoxMousedown(e)</h3>
|
||||
<blockquote>
|
||||
<p>v0.10.2+</p>
|
||||
</blockquote>
|
||||
<p>视口框元素鼠标按下事件调用该方法。</p>
|
||||
<h3>onViewBoxMousemove(e)</h3>
|
||||
<blockquote>
|
||||
<p>v0.10.2+</p>
|
||||
</blockquote>
|
||||
<p>视口框元素鼠标移动事件调用该方法。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
89
web/src/pages/Doc/zh/outerFrame/index.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# OuterFrame 插件
|
||||
|
||||
> v0.10.2+
|
||||
|
||||
该插件用于实现外框功能。
|
||||
|
||||
## 注册
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
|
||||
MindMap.usePlugin(OuterFrame)
|
||||
```
|
||||
|
||||
注册完且实例化`MindMap`后可通过`mindMap.outerFrame`获取到该实例。
|
||||
|
||||
应用使用可参考Demo该部分的代码:[NodeOuterFrame.vue](https://github.com/wanglin2/mind-map/blob/main/web/src/pages/Edit/components/NodeOuterFrame.vue)。
|
||||
|
||||
## 命令
|
||||
|
||||
该插件会向思维导图注册`ADD_OUTER_FRAME`命令,用于给节点添加外框:
|
||||
|
||||
```js
|
||||
mindMap.execCommand('ADD_OUTER_FRAME', appointNodes, config = {})
|
||||
```
|
||||
|
||||
- `appointNodes`:指定要添加外框的节点实例节点,可以是单个节点实例,也可以是节点实例数组,如果传递`[]`或`null`,则会向画布当前激活的节点添加外框
|
||||
|
||||
- `config`:外框配置,对象格式,字段如下:
|
||||
|
||||
| 字段名称 | 类型 | 默认值 | 描述 |
|
||||
| ------------------ | ------- | --------------- | ------------|
|
||||
| radius | Number | 5 | 外框圆角大小 |
|
||||
| strokeWidth | Number | 2 | 外框边框宽度 |
|
||||
| strokeColor | String | #0984e3 | 外框边框颜色 |
|
||||
| strokeDasharray | String | 5,5 | 外框边框虚线 |
|
||||
| fill | String | rgba(9,132,227,0.05) | 外框填充颜色 |
|
||||
|
||||
## 事件
|
||||
|
||||
### outer_frame_active
|
||||
|
||||
当点击激活某个外框时触发。回调函数接收三个参数:el(外框元素,@svgdotjs/svg.js库的rect元素), node(该范围所属节点的父节点实例), range(范围区间,相对于node)
|
||||
|
||||
应用可以监听该事件来获取当前激活的外框,获取到其配置回显到页面,因为范围可能包含多个节点,所以通常取第一个节点实例,如果要获取外框在页面上的位置,可以调用`el.rbox`方法:
|
||||
|
||||
```js
|
||||
mindMap.on('outer_frame_active', (el, parentNode, range) => {
|
||||
// 取范围内第一个节点的外框样式
|
||||
const firstNode = parentNode.children[range[0]]
|
||||
const firstNodeOuterFrame = firstNode.getData('outerFrame')
|
||||
// 获取外框的位置大小信息,你可以在该位置渲染你的配置浮层
|
||||
const { x, y, width, height } = el.rbox()
|
||||
})
|
||||
```
|
||||
|
||||
### outer_frame_delete
|
||||
|
||||
删除画布当前激活的外框时触发。
|
||||
|
||||
## 方法
|
||||
|
||||
### getActiveOuterFrame()
|
||||
|
||||
获取当前激活的外框数据。返回一个对象,结构如下:
|
||||
|
||||
```js
|
||||
{
|
||||
el,
|
||||
node,
|
||||
range
|
||||
}
|
||||
```
|
||||
|
||||
### updateActiveOuterFrame(config = {})
|
||||
|
||||
更新当前激活的外框。执行了该方法后请立即隐藏你的样式面板,因为会清除当前激活的外框。
|
||||
|
||||
### removeActiveOuterFrame()
|
||||
|
||||
删除当前激活的外框。
|
||||
|
||||
### getRangeNodeList(node, range)
|
||||
|
||||
获取某个节点指定范围的带外框的子节点列表。
|
||||
|
||||
### clearActiveOuterFrame()
|
||||
|
||||
清除当前激活的外框。
|
||||