Compare commits

..

55 Commits

Author SHA1 Message Date
wanglin2
efe205ae70 打包0.6.4-fix.1 2023-06-27 09:08:45 +08:00
wanglin2
a0d7473b1f Doc: update 2023-06-27 09:05:39 +08:00
wanglin2
7821781f20 Feat:鼠标滚轮缩放时默认以鼠标当前位置为中心进行缩放,可以通过配置关闭该特性 2023-06-27 09:05:25 +08:00
街角小林
b90d4ddf8a Merge pull request #152 from F-star/feat/scale-in-wheel-curor
Feat: 支持滚轮情况下,以光标为中心进行缩放
2023-06-27 08:47:40 +08:00
Hao Huang
314562c167 Feat: 支持滚轮情况下,以光标为中心进行缩放 2023-06-26 13:32:33 +00:00
wanglin2
5f0a9a7ce2 打包0.6.4 2023-06-26 16:20:38 +08:00
wanglin2
98e27841ad Doc: update 2023-06-26 16:15:20 +08:00
wanglin2
1b6467728c Feat:优化指定中心点缩放 2023-06-26 15:57:45 +08:00
街角小林
4bb349b2df Merge pull request #151 from F-star/main
Feat: 以画布为中心进行缩放
2023-06-26 15:25:08 +08:00
Hao Huang
b262336f08 Feat: 以画布为中心进行缩放 2023-06-26 05:47:06 +00:00
wanglin2
2b59087461 Merge branch 'feature' into main 2023-06-26 10:33:03 +08:00
wanglin2
66c9805efc Doc: update 2023-06-26 10:32:36 +08:00
wanglin2
710128901a 更新群二维码 2023-06-26 09:56:10 +08:00
wanglin2
61be0f7ac4 Merge branch 'feature' into main 2023-06-24 17:08:18 +08:00
wanglin2
7289b3a0ad Doc:update 2023-06-24 17:06:52 +08:00
wanglin2
25243e2053 Merge branch 'feature' into main 2023-06-21 15:56:20 +08:00
wanglin2
060a448cd5 打包0.6.3 2023-06-21 15:55:38 +08:00
wanglin2
bdb6078df6 '更新文档' 2023-06-21 15:33:51 +08:00
wanglin2
749a4d0e81 Feat:支持自定义节点内容 2023-06-21 14:57:22 +08:00
wanglin2
1749705694 Fix:修复概要节点会响应快捷键添加节点的问题 2023-06-21 10:50:26 +08:00
wanglin2
eec736be4d README: update 2023-06-20 16:43:10 +08:00
wanglin2
ffdf53941a Merge branch 'feature' into main 2023-06-20 16:39:55 +08:00
wanglin2
5676e952f3 打包0.6.2 2023-06-20 16:38:29 +08:00
wanglin2
e049ee6260 Doc: update 2023-06-20 16:35:36 +08:00
wanglin2
f1355c9d2a Fix:修复切换主题时节点样式没有随之切换的问题 2023-06-20 16:29:54 +08:00
wanglin2
d696e0fdc1 合并 2023-06-19 22:37:13 +08:00
wanglin2
c8d2f284fd 打包0.6.1 2023-06-19 22:34:19 +08:00
wanglin2
aa8ecd4f60 合并 2023-06-19 22:32:37 +08:00
wanglin2
2323fe9bc0 Fix:修复将鼠标滚动改为移动画布行为后,使用触控板操作时移动灵敏度过高的问题 2023-06-19 22:31:12 +08:00
wanglin2
b9a0b16fc8 更新群二维码 2023-06-19 11:37:28 +08:00
wanglin2
b9c340afbf Doc:更新文档 2023-06-19 09:28:36 +08:00
wanglin2
ee98d7128b Merge branch 'feature' into main 2023-06-15 17:09:52 +08:00
wanglin2
d37febe306 打包0.6.0-fix.1 2023-06-15 17:09:27 +08:00
wanglin2
5de97f05b3 更新文档 2023-06-12 18:13:05 +08:00
wanglin2
662447bc69 Fix:修复没有设置过背景样式的情况下销毁思维导图报错的问题 2023-06-12 17:42:01 +08:00
wanglin2
51c1c46287 Merge branch 'feature' into main 2023-06-12 17:07:54 +08:00
wanglin2
3b03d9798b 打包0.6.0 2023-06-12 17:06:23 +08:00
wanglin2
17fbef810c Fix:修复清空节点再输入中文时发生抖动的问题 2023-06-12 17:02:14 +08:00
wanglin2
e798975a9f 更新群二维码 2023-06-12 15:14:37 +08:00
wanglin2
2af65e322b Merge branch 'feature' into main 2023-06-12 15:12:57 +08:00
wanglin2
23f09f9b4d 打包0.6.0 2023-06-12 14:42:44 +08:00
wanglin2
d69668a488 Feat:新增触摸事件支持插件 2023-06-12 14:14:55 +08:00
wanglin2
5353888965 更新文档 2023-06-12 09:10:04 +08:00
wanglin2
b33fd1908a Fix:修复富文本编辑时删除完所有文本后再输入时样式丢失问题 2023-06-11 22:21:03 +08:00
wanglin2
97583ffcba Feat:新增销毁思维导图的方法 2023-06-11 13:14:19 +08:00
wanglin2
360eca620e Feature:将导出pdf功能提取为一个单独的插件 2023-06-11 10:41:53 +08:00
wanglin2
6d0682e821 Fix:修复左键多选节点后多选状态被取消的问题 2023-06-11 10:21:49 +08:00
wanglin2
834bdf37c3 Feat:支持控制节点是否允许编辑 2023-06-09 17:18:02 +08:00
wanglin2
e3d31f69bf Feat:支持设置为左键多选节点,右键拖动画布 2023-06-09 16:49:15 +08:00
wanglin2
ac55415de1 Fix:1.去除不需要的依赖;2.修复按住ctrl键多选节点时不会触发节点的click事件的问题 2023-06-09 13:39:07 +08:00
wanglin2
4d91be5be6 Feat:可通过配置决定是否开启按住ctrl键多选节点的功能 2023-06-08 20:18:13 +08:00
wanglin2
ee467cb155 Feat:支持一键缩放思维导图至画布大小 2023-06-08 20:06:20 +08:00
wanglin2
6281f2360c 更新文档 2023-06-08 18:27:25 +08:00
wanglin2
cd8af6ae06 合并 2023-06-08 16:51:31 +08:00
wanglin2
45cc199d7f 重新调整核心库代码目录结构 2023-06-08 16:49:54 +08:00
138 changed files with 2024 additions and 443 deletions

View File

@@ -92,10 +92,14 @@ MIT
<img src="./qrcode.jpg" style="width: 300px" />
如果已过期,可以微信添加`wanglinguanfang`拉你入群。
# 请作者喝杯咖啡
> 厚椰乳一盒 + 纯牛奶半盒 + 冰块 + 咖啡液 = 生椰拿铁 yyds
> 转账请备注哦~你的头像和名称会出现在[文档页面](https://wanglin2.github.io/mind-map/#/doc/zh/introduction/%E8%AF%B7%E4%BD%9C%E8%80%85%E5%96%9D%E6%9D%AF%E5%92%96%E5%95%A1)
<p>
<img src="./web/src/assets/img/alipay.jpg" style="width: 300px" />
<img src="./web/src/assets/img/wechat.jpg" style="width: 300px" />

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -1,12 +1,13 @@
import MindMap from './index'
import MiniMap from './src/MiniMap.js'
import Watermark from './src/Watermark.js'
import KeyboardNavigation from './src/KeyboardNavigation.js'
import Export from './src/Export.js'
import Drag from './src/Drag.js'
import Select from './src/Select.js'
import AssociativeLine from './src/AssociativeLine'
import RichText from './src/RichText'
import MiniMap from './src/plugins/MiniMap.js'
import Watermark from './src/plugins/Watermark.js'
import KeyboardNavigation from './src/plugins/KeyboardNavigation.js'
import ExportPDF from './src/plugins/ExportPDF.js'
import Export from './src/plugins/Export.js'
import Drag from './src/plugins/Drag.js'
import Select from './src/plugins/Select.js'
import AssociativeLine from './src/plugins/AssociativeLine'
import RichText from './src/plugins/RichText'
import xmind from './src/parse/xmind.js'
import markdown from './src/parse/markdown.js'
import icons from './src/svg/icons.js'
@@ -20,6 +21,7 @@ MindMap
.usePlugin(Watermark)
.usePlugin(Drag)
.usePlugin(KeyboardNavigation)
.usePlugin(ExportPDF)
.usePlugin(Export)
.usePlugin(Select)
.usePlugin(AssociativeLine)

View File

@@ -1,129 +1,17 @@
import View from './src/View'
import Event from './src/Event'
import Render from './src/Render'
import View from './src/core/view/View'
import Event from './src/core/event/Event'
import Render from './src/core/render/Render'
import merge from 'deepmerge'
import theme from './src/themes'
import Style from './src/Style'
import KeyCommand from './src/KeyCommand'
import Command from './src/Command'
import BatchExecution from './src/BatchExecution'
import { layoutValueList, CONSTANTS } from './src/utils/constant'
import Style from './src/core/render/node/Style'
import KeyCommand from './src/core/command/KeyCommand'
import Command from './src/core/command/Command'
import BatchExecution from './src/utils/BatchExecution'
import { layoutValueList, CONSTANTS } from './src/constants/constant'
import { SVG } from '@svgdotjs/svg.js'
import { simpleDeepClone } from './src/utils'
import defaultTheme, { checkIsNodeSizeIndependenceConfig } from './src/themes/default'
// 默认选项配置
const defaultOpt = {
// 是否只读
readonly: false,
// 布局
layout: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
// 如果结构为鱼骨图,那么可以通过该选项控制倾斜角度
fishboneDeg: 45,
// 主题
theme: 'default', // 内置主题default默认主题
// 主题配置,会和所选择的主题进行合并
themeConfig: {},
// 放大缩小的增量比例
scaleRatio: 0.1,
// 最多显示几个标签
maxTag: 5,
// 导出图片时的内边距
exportPadding: 20,
// 展开收缩按钮尺寸
expandBtnSize: 20,
// 节点里图片和文字的间距
imgTextMargin: 5,
// 节点里各种文字信息的间距,如图标和文字的间距
textContentMargin: 2,
// 多选节点时鼠标移动到边缘时的画布移动偏移量
selectTranslateStep: 3,
// 多选节点时鼠标移动距边缘多少距离时开始偏移
selectTranslateLimit: 20,
// 自定义节点备注内容显示
customNoteContentShow: null,
/*
{
show(){},
hide(){}
}
*/
// 是否开启节点自由拖拽
enableFreeDrag: false,
// 水印配置
watermarkConfig: {
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '#999',
opacity: 0.5,
fontSize: 14
}
},
// 达到该宽度文本自动换行
textAutoWrapWidth: 500,
// 自定义鼠标滚轮事件处理
// 可以传一个函数,回调参数为事件对象
customHandleMousewheel: null,
// 鼠标滚动的行为如果customHandleMousewheel传了自定义函数这个属性不生效
mousewheelAction: CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM,// zoom放大缩小、move上下移动
// 当mousewheelAction设为move时可以通过该属性控制鼠标滚动一下视图移动的步长单位px
mousewheelMoveStep: 100,
// 默认插入的二级节点的文字
defaultInsertSecondLevelNodeText: '二级节点',
// 默认插入的二级以下节点的文字
defaultInsertBelowSecondLevelNodeText: '分支主题',
// 展开收起按钮的颜色
expandBtnStyle: {
color: '#808080',
fill: '#fff'
},
// 自定义展开收起按钮的图标
expandBtnIcon: {
open: '',// svg字符串
close: ''
},
// 是否只有当鼠标在画布内才响应快捷键事件
enableShortcutOnlyWhenMouseInSvg: true,
// 是否开启节点动画过渡
enableNodeTransitionMove: true,
// 如果开启节点动画过渡可以通过该属性设置过渡的时间单位ms
nodeTransitionMoveDuration: 300,
// 初始根节点的位置
initRootNodePosition: null,
// 导出png、svg、pdf时的图形内边距
exportPaddingX: 10,
exportPaddingY: 10,
// 节点文本编辑框的z-index
nodeTextEditZIndex: 3000,
// 节点备注浮层的z-index
nodeNoteTooltipZIndex: 3000,
// 是否在点击了画布外的区域时结束节点文本的编辑状态
isEndNodeTextEditOnClickOuter: true,
// 最大历史记录数
maxHistoryCount: 1000,
// 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示
alwaysShowExpandBtn: false,
// 扩展节点可插入的图标
iconList: [
// {
// name: '',// 分组名称
// type: '',// 分组的值
// list: [// 分组下的图标列表
// {
// name: '',// 图标名称
// icon:''// 图标可以传svg或图片
// }
// ]
// }
],
// 节点最大缓存数量
maxNodeCacheCount: 1000,
// 关联线默认文字
defaultAssociativeLineText: '关联'
}
import { defaultOpt } from './src/constants/defaultOptions'
// 思维导图
class MindMap {
@@ -476,6 +364,21 @@ class MindMap {
pluginOpt: plugin.pluginOpt
})
}
// 销毁
destroy() {
// 移除插件
[...MindMap.pluginList].forEach((plugin) => {
this[plugin.instanceName] = null
})
// 解绑事件
this.event.unbind()
// 移除画布节点
this.svg.remove()
// 去除给容器元素设置的背景样式
Style.removeBackgroundStyle(this.el)
this.el = null
}
}
// 插件列表

View File

@@ -1,15 +1,14 @@
{
"name": "simple-mind-map",
"version": "0.4.7",
"version": "0.6.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "0.4.7",
"version": "0.6.0",
"license": "MIT",
"dependencies": {
"@svgdotjs/svg.js": "^3.0.16",
"canvg": "^3.0.7",
"deepmerge": "^1.5.2",
"eventemitter3": "^4.0.7",
"html2canvas": "^1.4.1",
@@ -160,7 +159,8 @@
"node_modules/@types/raf": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz",
"integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw=="
"integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==",
"optional": true
},
"node_modules/@types/unist": {
"version": "2.0.6",
@@ -305,6 +305,7 @@
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
"optional": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
@@ -381,6 +382,7 @@
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
"hasInstallScript": true,
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
@@ -1813,7 +1815,8 @@
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"optional": true
},
"node_modules/prelude-ls": {
"version": "1.2.1",
@@ -1908,6 +1911,7 @@
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"optional": true,
"dependencies": {
"performance-now": "^2.1.0"
}
@@ -1982,6 +1986,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"optional": true,
"engines": {
"node": ">= 0.8.15"
}
@@ -2075,6 +2080,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
"integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==",
"optional": true,
"engines": {
"node": ">=0.1.14"
}
@@ -2127,6 +2133,7 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"optional": true,
"engines": {
"node": ">=12.0.0"
}
@@ -2386,7 +2393,8 @@
"@types/raf": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz",
"integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw=="
"integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==",
"optional": true
},
"@types/unist": {
"version": "2.0.6",
@@ -2489,6 +2497,7 @@
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
"optional": true,
"requires": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
@@ -2544,7 +2553,8 @@
"core-js": {
"version": "3.27.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww=="
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
"optional": true
},
"core-util-is": {
"version": "1.0.3",
@@ -3511,7 +3521,8 @@
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"optional": true
},
"prelude-ls": {
"version": "1.2.1",
@@ -3576,6 +3587,7 @@
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"optional": true,
"requires": {
"performance-now": "^2.1.0"
}
@@ -3630,7 +3642,8 @@
"rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw=="
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"optional": true
},
"rimraf": {
"version": "3.0.2",
@@ -3691,7 +3704,8 @@
"stackblur-canvas": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
"integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ=="
"integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==",
"optional": true
},
"string_decoder": {
"version": "1.1.1",
@@ -3728,7 +3742,8 @@
"svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw=="
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"optional": true
},
"text-segmentation": {
"version": "1.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "simple-mind-map",
"version": "0.5.11",
"version": "0.6.4-fix.1",
"description": "一个简单的web在线思维导图",
"authors": [
{
@@ -25,7 +25,6 @@
"__main": "./dist/simpleMindMap.umd.min.js",
"dependencies": {
"@svgdotjs/svg.js": "^3.0.16",
"canvg": "^3.0.7",
"deepmerge": "^1.5.2",
"eventemitter3": "^4.0.7",
"html2canvas": "^1.4.1",

View File

@@ -259,4 +259,24 @@ export const layoutValueList = [
CONSTANTS.LAYOUT.TIMELINE,
CONSTANTS.LAYOUT.TIMELINE2,
CONSTANTS.LAYOUT.FISHBONE
]
// 节点数据中非样式的字段
export const nodeDataNoStylePropList = [
'text',
'image',
'imageTitle',
'imageSize',
'icon',
'tag',
'hyperlink',
'hyperlinkTitle',
'note',
'expand',
'isActive',
'generalization',
'richText',
'resetRichText',
'uid',
'activeStyle'
]

View File

@@ -0,0 +1,128 @@
import { CONSTANTS } from './constant'
// 默认选项配置
export const defaultOpt = {
// 是否只读
readonly: false,
// 布局
layout: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
// 如果结构为鱼骨图,那么可以通过该选项控制倾斜角度
fishboneDeg: 45,
// 主题
theme: 'default', // 内置主题default默认主题
// 主题配置,会和所选择的主题进行合并
themeConfig: {},
// 放大缩小的增量比例
scaleRatio: 0.2,
// 鼠标缩放是否以鼠标当前位置为中心点,否则以画布中心点
mouseScaleCenterUseMousePosition: true,
// 最多显示几个标签
maxTag: 5,
// 导出图片时的内边距
exportPadding: 20,
// 展开收缩按钮尺寸
expandBtnSize: 20,
// 节点里图片和文字的间距
imgTextMargin: 5,
// 节点里各种文字信息的间距,如图标和文字的间距
textContentMargin: 2,
// 多选节点时鼠标移动到边缘时的画布移动偏移量
selectTranslateStep: 3,
// 多选节点时鼠标移动距边缘多少距离时开始偏移
selectTranslateLimit: 20,
// 自定义节点备注内容显示
customNoteContentShow: null,
/*
{
show(){},
hide(){}
}
*/
// 是否开启节点自由拖拽
enableFreeDrag: false,
// 水印配置
watermarkConfig: {
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '#999',
opacity: 0.5,
fontSize: 14
}
},
// 达到该宽度文本自动换行
textAutoWrapWidth: 500,
// 自定义鼠标滚轮事件处理
// 可以传一个函数,回调参数为事件对象
customHandleMousewheel: null,
// 鼠标滚动的行为如果customHandleMousewheel传了自定义函数这个属性不生效
mousewheelAction: CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM, // zoom放大缩小、move上下移动
// 当mousewheelAction设为move时可以通过该属性控制鼠标滚动一下视图移动的步长单位px
mousewheelMoveStep: 100,
// 默认插入的二级节点的文字
defaultInsertSecondLevelNodeText: '二级节点',
// 默认插入的二级以下节点的文字
defaultInsertBelowSecondLevelNodeText: '分支主题',
// 展开收起按钮的颜色
expandBtnStyle: {
color: '#808080',
fill: '#fff'
},
// 自定义展开收起按钮的图标
expandBtnIcon: {
open: '', // svg字符串
close: ''
},
// 是否只有当鼠标在画布内才响应快捷键事件
enableShortcutOnlyWhenMouseInSvg: true,
// 是否开启节点动画过渡
enableNodeTransitionMove: true,
// 如果开启节点动画过渡可以通过该属性设置过渡的时间单位ms
nodeTransitionMoveDuration: 300,
// 初始根节点的位置
initRootNodePosition: null,
// 导出png、svg、pdf时的图形内边距
exportPaddingX: 10,
exportPaddingY: 10,
// 节点文本编辑框的z-index
nodeTextEditZIndex: 3000,
// 节点备注浮层的z-index
nodeNoteTooltipZIndex: 3000,
// 是否在点击了画布外的区域时结束节点文本的编辑状态
isEndNodeTextEditOnClickOuter: true,
// 最大历史记录数
maxHistoryCount: 1000,
// 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示
alwaysShowExpandBtn: false,
// 扩展节点可插入的图标
iconList: [
// {
// name: '',// 分组名称
// type: '',// 分组的值
// list: [// 分组下的图标列表
// {
// name: '',// 图标名称
// icon:''// 图标可以传svg或图片
// }
// ]
// }
],
// 节点最大缓存数量
maxNodeCacheCount: 1000,
// 关联线默认文字
defaultAssociativeLineText: '关联',
// 思维导图适应画布大小时的内边距
fitPadding: 50,
// 是否开启按住ctrl键多选节点功能
enableCtrlKeyNodeSelection: true,
// 设置为左键多选节点,右键拖动画布
useLeftKeySelectionRightKeyDrag: false,
// 节点即将进入编辑前的回调方法如果该方法返回true以外的值那么将取消编辑函数可以返回一个值或一个Promise回调参数为节点实例
beforeTextEdit: null,
// 是否开启自定义节点内容
isUseCustomNodeContent: false,
// 自定义返回节点内容的方法
customCreateNodeContent: null
}

View File

@@ -1,4 +1,4 @@
import { copyRenderTree, simpleDeepClone, nextTick } from './utils'
import { copyRenderTree, simpleDeepClone, nextTick } from '../../utils'
// 命令类
class Command {

View File

@@ -1,4 +1,4 @@
import { keyMap } from './utils/keyMap'
import { keyMap } from './keyMap'
// 快捷按键、命令处理类
export default class KeyCommand {
// 构造函数

View File

@@ -1,5 +1,5 @@
import EventEmitter from 'eventemitter3'
import { CONSTANTS } from './utils/constant'
import { CONSTANTS } from '../../constants/constant'
// 事件类
class Event extends EventEmitter {
@@ -9,6 +9,7 @@ class Event extends EventEmitter {
this.opt = opt
this.mindMap = opt.mindMap
this.isLeftMousedown = false
this.isRightMousedown = false
this.mousedownPos = {
x: 0,
y: 0
@@ -89,6 +90,8 @@ class Event extends EventEmitter {
// 鼠标左键
if (e.which === 1) {
this.isLeftMousedown = true
} else if (e.which === 3) {
this.isRightMousedown = true
}
this.mousedownPos.x = e.clientX
this.mousedownPos.y = e.clientY
@@ -97,12 +100,17 @@ class Event extends EventEmitter {
// 鼠标移动事件
onMousemove(e) {
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
this.mousemovePos.x = e.clientX
this.mousemovePos.y = e.clientY
this.mousemoveOffset.x = e.clientX - this.mousedownPos.x
this.mousemoveOffset.y = e.clientY - this.mousedownPos.y
this.emit('mousemove', e, this)
if (this.isLeftMousedown) {
if (
useLeftKeySelectionRightKeyDrag
? this.isRightMousedown
: this.isLeftMousedown
) {
e.preventDefault()
this.emit('drag', e, this)
}
@@ -111,6 +119,7 @@ class Event extends EventEmitter {
// 鼠标松开事件
onMouseup(e) {
this.isLeftMousedown = false
this.isRightMousedown = false
this.emit('mouseup', e, this)
}
@@ -131,7 +140,13 @@ class Event extends EventEmitter {
if ((e.wheelDeltaX || e.detail) > 0) dir = CONSTANTS.DIR.LEFT
if ((e.wheelDeltaX || e.detail) < 0) dir = CONSTANTS.DIR.RIGHT
}
this.emit('mousewheel', e, dir, this)
// 判断是否是触控板
let isTouchPad = false
// mac、windows
if (e.wheelDeltaY === e.deltaY * -3 || Math.abs(e.wheelDeltaY) <= 10) {
isTouchPad = true
}
this.emit('mousewheel', e, dir, this, isTouchPad)
}
// 鼠标右键菜单事件

View File

@@ -1,15 +1,15 @@
import merge from 'deepmerge'
import LogicalStructure from './layouts/LogicalStructure'
import MindMap from './layouts/MindMap'
import CatalogOrganization from './layouts/CatalogOrganization'
import OrganizationStructure from './layouts/OrganizationStructure'
import Timeline from './layouts/Timeline'
import Fishbone from './layouts/Fishbone'
import LogicalStructure from '../../layouts/LogicalStructure'
import MindMap from '../../layouts/MindMap'
import CatalogOrganization from '../../layouts/CatalogOrganization'
import OrganizationStructure from '../../layouts/OrganizationStructure'
import Timeline from '../../layouts/Timeline'
import Fishbone from '../../layouts/Fishbone'
import TextEdit from './TextEdit'
import { copyNodeTree, simpleDeepClone, walk } from './utils'
import { shapeList } from './Shape'
import { lineStyleProps } from './themes/default'
import { CONSTANTS } from './utils/constant'
import { copyNodeTree, simpleDeepClone, walk } from '../../utils'
import { shapeList } from './node/Shape'
import { lineStyleProps } from '../../themes/default'
import { CONSTANTS } from '../../constants/constant'
// 布局列表
const layouts = {
@@ -79,9 +79,15 @@ class Render {
// 绑定事件
bindEvent() {
// 点击事件
this.mindMap.on('draw_click', () => {
this.mindMap.on('draw_click', (e) => {
// 清除激活状态
if (this.activeNodeList.length > 0) {
let isTrueClick = true
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
if (useLeftKeySelectionRightKeyDrag) {
let mousedownPos = this.mindMap.event.mousedownPos
isTrueClick = Math.abs(e.clientX - mousedownPos.x) <= 5 && Math.abs(e.clientY - mousedownPos.y) <= 5
}
if (isTrueClick && this.activeNodeList.length > 0) {
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
}
})
@@ -419,6 +425,9 @@ class Render {
let { defaultInsertSecondLevelNodeText, defaultInsertBelowSecondLevelNodeText } = this.mindMap.opt
let list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
let first = list[0]
if (first.isGeneralization) {
return
}
if (first.isRoot) {
this.insertChildNode(openEdit, appointNodes, appointData)
} else {
@@ -449,6 +458,9 @@ class Render {
let { defaultInsertSecondLevelNodeText, defaultInsertBelowSecondLevelNodeText } = this.mindMap.opt
let list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
list.forEach(node => {
if (node.isGeneralization) {
return
}
if (!node.nodeData.children) {
node.nodeData.children = []
}

View File

@@ -1,4 +1,4 @@
import { getStrWithBrFromHtml, checkNodeOuter } from './utils'
import { getStrWithBrFromHtml, checkNodeOuter } from '../../utils'
// 节点文字编辑类
export default class TextEdit {
@@ -65,7 +65,21 @@ export default class TextEdit {
}
// 显示文本编辑框
show(node) {
async show(node) {
// 使用了自定义节点内容那么不响应编辑事件
if (node.isUseCustomNodeContent()) {
return
}
let { beforeTextEdit } = this.mindMap.opt
if (typeof beforeTextEdit === 'function') {
let isShow = false
try {
isShow = await beforeTextEdit(node)
} catch (error) {
isShow = false
}
if (!isShow) return
}
this.currentNode = node
let { offsetLeft, offsetTop } = checkNodeOuter(this.mindMap, node)
this.mindMap.view.translateXY(offsetLeft, offsetTop)

View File

@@ -1,12 +1,12 @@
import Style from './Style'
import Shape from './Shape'
import { asyncRun } from './utils'
import { G, Rect } from '@svgdotjs/svg.js'
import nodeGeneralizationMethods from './utils/nodeGeneralization'
import nodeExpandBtnMethods from './utils/nodeExpandBtn'
import nodeCommandWrapsMethods from './utils/nodeCommandWraps'
import nodeCreateContentsMethods from './utils/nodeCreateContents'
import { CONSTANTS } from './utils/constant'
import { asyncRun, nodeToHTML } from '../../../utils'
import { G, Rect, ForeignObject, SVG } from '@svgdotjs/svg.js'
import nodeGeneralizationMethods from './nodeGeneralization'
import nodeExpandBtnMethods from './nodeExpandBtn'
import nodeCommandWrapsMethods from './nodeCommandWraps'
import nodeCreateContentsMethods from './nodeCreateContents'
import { CONSTANTS } from '../../../constants/constant'
// 节点类
class Node {
@@ -59,6 +59,7 @@ class Node {
this.group = null
this.shapeNode = null // 节点形状节点
// 节点内容对象
this._customNodeContent = null
this._imgData = null
this._iconData = null
this._textData = null
@@ -154,6 +155,13 @@ class Node {
// 创建节点的各个内容对象数据
createNodeData() {
// 自定义节点内容
let { isUseCustomNodeContent, customCreateNodeContent } = this.mindMap.opt
if (isUseCustomNodeContent && customCreateNodeContent) {
this._customNodeContent = customCreateNodeContent(this)
}
// 如果没有返回内容,那么还是使用内置的节点内容
if (this._customNodeContent) return
this._imgData = this.createImgNode()
this._iconData = this.createIconNode()
this._textData = this.createTextNode()
@@ -176,6 +184,14 @@ class Node {
// 计算节点尺寸信息
getNodeRect() {
// 自定义节点内容
if (this.isUseCustomNodeContent()) {
let rect = this.measureCustomNodeContentSize(this._customNodeContent)
return {
width: rect.width,
height: rect.height
}
}
// 宽高
let imgContentWidth = 0
let imgContentHeight = 0
@@ -266,6 +282,15 @@ class Node {
if (this.isGeneralization && this.generalizationBelongNode) {
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
}
// 如果存在自定义节点内容,那么使用自定义节点内容
if (this.isUseCustomNodeContent()) {
let foreignObject = new ForeignObject()
foreignObject.width(width)
foreignObject.height(height)
foreignObject.add(SVG(this._customNodeContent))
this.group.add(foreignObject)
return
}
// 图片节点
let imgHeight = 0
if (this._imgData) {
@@ -343,12 +368,12 @@ class Node {
bindGroupEvent() {
// 单击事件,选中节点
this.group.on('click', e => {
this.mindMap.emit('node_click', this, e)
if (this.isMultipleChoice) {
e.stopPropagation()
this.isMultipleChoice = false
return
}
this.mindMap.emit('node_click', this, e)
this.active(e)
})
this.group.on('mousedown', e => {
@@ -359,7 +384,7 @@ class Node {
e.stopPropagation()
}
// 多选和取消多选
if (e.ctrlKey) {
if (e.ctrlKey && this.mindMap.opt.enableCtrlKeyNodeSelection) {
this.isMultipleChoice = true
let isActive = this.nodeData.data.isActive
if (!isActive)
@@ -798,6 +823,11 @@ class Node {
getData(key) {
return key ? this.nodeData.data[key] || '' : this.nodeData.data
}
// 是否存在自定义样式
hasCustomStyle() {
return this.style.hasCustomStyle()
}
}
export default Node

View File

@@ -1,5 +1,5 @@
import { Rect, Polygon, Path } from '@svgdotjs/svg.js'
import { CONSTANTS } from './utils/constant'
import { CONSTANTS } from '../../../constants/constant'
// 节点形状类
export default class Shape {

View File

@@ -1,10 +1,20 @@
import { tagColorList } from './utils/constant'
import { tagColorList, nodeDataNoStylePropList } from '../../../constants/constant'
const rootProp = ['paddingX', 'paddingY']
const backgroundStyleProps = ['backgroundColor', 'backgroundImage', 'backgroundRepeat', 'backgroundPosition', 'backgroundSize']
// 样式类
class Style {
// 设置背景样式
static setBackgroundStyle(el, themeConfig) {
// 缓存容器元素原本的样式
if (!Style.cacheStyle) {
Style.cacheStyle = {}
let style = window.getComputedStyle(el)
backgroundStyleProps.forEach((prop) => {
Style.cacheStyle[prop] = style[prop]
})
}
// 设置新样式
let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig
el.style.backgroundColor = backgroundColor
if (backgroundImage) {
@@ -17,6 +27,15 @@ class Style {
}
}
// 移除背景样式
static removeBackgroundStyle(el) {
if (!Style.cacheStyle) return
backgroundStyleProps.forEach((prop) => {
el.style[prop] = Style.cacheStyle[prop]
})
Style.cacheStyle = null
}
// 构造函数
constructor(ctx) {
this.ctx = ctx
@@ -190,6 +209,19 @@ class Style {
node2.fill({ color: color })
fillNode.fill({ color: fill })
}
// 是否设置了自定义的样式
hasCustomStyle() {
let res = false
Object.keys(this.ctx.nodeData.data).forEach((item) => {
if (!nodeDataNoStylePropList.includes(item)) {
res = true
}
})
return res
}
}
Style.cacheStyle = null
export default Style

View File

@@ -1,7 +1,7 @@
import { measureText, resizeImgSize, getTextFromHtml } from '../utils'
import { measureText, resizeImgSize, getTextFromHtml } from '../../../utils'
import { Image, SVG, A, G, Rect, Text, ForeignObject } from '@svgdotjs/svg.js'
import iconsSvg from '../svg/icons'
import { CONSTANTS } from './constant'
import iconsSvg from '../../../svg/icons'
import { CONSTANTS } from '../../../constants/constant'
// 创建图片节点
function createImgNode() {
@@ -64,8 +64,18 @@ function createIconNode() {
function createRichTextNode() {
let g = new G()
// 重新设置富文本节点内容
if (this.nodeData.data.resetRichText || [CONSTANTS.CHANGE_THEME].includes(this.mindMap.renderer.renderSource)) {
let recoverText = false
if (this.nodeData.data.resetRichText) {
delete this.nodeData.data.resetRichText
recoverText = true
}
if ([CONSTANTS.CHANGE_THEME].includes(this.mindMap.renderer.renderSource)) {
// 如果自定义过样式则不允许覆盖
if (!this.hasCustomStyle()) {
recoverText = true
}
}
if (recoverText) {
let text = getTextFromHtml(this.nodeData.data.text)
this.nodeData.data.text = `<p><span style="${this.style.createStyleText()}">${text}</span></p>`
}
@@ -270,6 +280,32 @@ function createNoteNode() {
}
}
// 测量自定义节点内容元素的宽高
let warpEl = null
function measureCustomNodeContentSize (content) {
if (!warpEl) {
warpEl = document.createElement('div')
warpEl.style.cssText = `
position: fixed;
left: -99999px;
top: -99999px;
`
this.mindMap.el.appendChild(warpEl)
}
warpEl.innerHTML = ''
warpEl.appendChild(content)
let rect = warpEl.getBoundingClientRect()
return {
width: rect.width,
height: rect.height
}
}
// 是否使用的是自定义节点内容
function isUseCustomNodeContent() {
return !!this._customNodeContent
}
export default {
createImgNode,
getImgShowSize,
@@ -278,5 +314,7 @@ export default {
createTextNode,
createHyperlinkNode,
createTagNode,
createNoteNode
createNoteNode,
measureCustomNodeContentSize,
isUseCustomNodeContent
}

View File

@@ -1,4 +1,4 @@
import btnsSvg from '../svg/btns'
import btnsSvg from '../../../svg/btns'
import { SVG, Circle, G } from '@svgdotjs/svg.js'
// 创建展开收起按钮的内容节点

View File

@@ -1,4 +1,4 @@
import Node from '../Node'
import Node from './Node'
// 检查是否存在概要
function checkHasGeneralization () {

View File

@@ -1,4 +1,4 @@
import { CONSTANTS } from './utils/constant'
import { CONSTANTS } from '../../constants/constant'
// 视图操作类
class View {
@@ -28,6 +28,9 @@ class View {
this.mindMap.keyCommand.addShortcut('Control+Enter', () => {
this.reset()
})
this.mindMap.keyCommand.addShortcut('Control+i', () => {
this.fit()
})
this.mindMap.svg.on('dblclick', () => {
this.reset()
})
@@ -56,40 +59,57 @@ class View {
this.firstDrag = true
})
// 放大缩小视图
this.mindMap.event.on('mousewheel', (e, dir) => {
if (this.mindMap.opt.customHandleMousewheel && typeof this.mindMap.opt.customHandleMousewheel === 'function') {
return this.mindMap.opt.customHandleMousewheel(e)
this.mindMap.event.on('mousewheel', (e, dir, event, isTouchPad) => {
let {
customHandleMousewheel,
mousewheelAction,
mouseScaleCenterUseMousePosition,
mousewheelMoveStep
} = this.mindMap.opt
// 是否自定义鼠标滚轮事件
if (
customHandleMousewheel &&
typeof customHandleMousewheel === 'function'
) {
return customHandleMousewheel(e)
}
if (this.mindMap.opt.mousewheelAction === CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM) {
// 鼠标滚轮事件控制缩放
if (mousewheelAction === CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM) {
let cx = mouseScaleCenterUseMousePosition ? e.clientX : undefined
let cy = mouseScaleCenterUseMousePosition ? e.clientY : undefined
switch (dir) {
// 鼠标滚轮,向上和向左,都是缩小
case CONSTANTS.DIR.UP:
case CONSTANTS.DIR.LEFT:
this.narrow()
this.narrow(cx, cy)
break
// 鼠标滚轮,向下和向右,都是放大
case CONSTANTS.DIR.DOWN:
case CONSTANTS.DIR.RIGHT:
this.enlarge()
this.enlarge(cx, cy)
break
}
} else {
switch (dir){
} else {// 鼠标滚轮事件控制画布移动
let step = mousewheelMoveStep
if (isTouchPad) {
step = 5
}
switch (dir) {
// 上移
case CONSTANTS.DIR.DOWN:
this.translateY(-this.mindMap.opt.mousewheelMoveStep)
this.translateY(-step)
break
// 下移
case CONSTANTS.DIR.UP:
this.translateY(this.mindMap.opt.mousewheelMoveStep)
this.translateY(step)
break
// 右移
case CONSTANTS.DIR.LEFT:
this.translateX(-this.mindMap.opt.mousewheelMoveStep)
this.translateX(-step)
break
// 左移
case CONSTANTS.DIR.RIGHT:
this.translateX(this.mindMap.opt.mousewheelMoveStep)
this.translateX(step)
break
}
}
@@ -158,8 +178,8 @@ class View {
// 应用变换
transform() {
this.mindMap.draw.transform({
origin: [0, 0],
scale: this.scale,
// origin: 'center center',
translate: [this.x, this.y]
})
this.mindMap.emit('view_data_change', this.getTransformData())
@@ -178,29 +198,96 @@ class View {
}
// 缩小
narrow() {
if (this.scale - this.mindMap.opt.scaleRatio > 0.1) {
this.scale -= this.mindMap.opt.scaleRatio
} else {
this.scale = 0.1
}
narrow(cx, cy) {
const scale = Math.max(this.scale - this.mindMap.opt.scaleRatio, 0.1)
this.scaleInCenter(scale, cx, cy)
this.transform()
this.mindMap.emit('scale', this.scale)
}
// 放大
enlarge() {
this.scale += this.mindMap.opt.scaleRatio
enlarge(cx, cy) {
const scale = this.scale + this.mindMap.opt.scaleRatio
this.scaleInCenter(scale, cx, cy)
this.transform()
this.mindMap.emit('scale', this.scale)
}
// 设置缩放
setScale(scale) {
// 基于指定中心进行缩放cxcy 可不指定,此时会使用画布中心点
scaleInCenter(scale, cx, cy) {
if (cx === undefined || cy === undefined) {
cx = this.mindMap.width / 2
cy = this.mindMap.height / 2
}
const prevScale = this.scale
const ratio = 1 - scale / prevScale
const dx = (cx - this.x) * ratio
const dy = (cy - this.y) * ratio
this.x += dx
this.y += dy
this.scale = scale
}
// 设置缩放
setScale(scale, cx, cy) {
if (cx !== undefined && cy !== undefined) {
this.scaleInCenter(scale, cx, cy)
} else {
this.scale = scale
}
this.transform()
this.mindMap.emit('scale', this.scale)
}
// 适应画布大小
fit() {
let { fitPadding } = this.mindMap.opt
let draw = this.mindMap.draw
let origTransform = draw.transform()
let rect = draw.rbox()
let drawWidth = rect.width / origTransform.scaleX
let drawHeight = rect.height / origTransform.scaleY
let drawRatio = drawWidth / drawHeight
let { width: elWidth, height: elHeight } =
this.mindMap.el.getBoundingClientRect()
elWidth = elWidth - fitPadding * 2
elHeight = elHeight - fitPadding * 2
let elRatio = elWidth / elHeight
let newScale = 0
let flag = ''
if (drawWidth <= elWidth && drawHeight <= elHeight) {
newScale = 1
flag = 1
} else {
let newWidth = 0
let newHeight = 0
if (drawRatio > elRatio) {
newWidth = elWidth
newHeight = elWidth / drawRatio
flag = 2
} else {
newHeight = elHeight
newWidth = elHeight * drawRatio
flag = 3
}
newScale = newWidth / drawWidth
}
this.setScale(newScale)
let newRect = draw.rbox()
let newX = 0
let newY = 0
if (flag === 1) {
newX = -newRect.x + fitPadding + (elWidth - newRect.width) / 2
newY = -newRect.y + fitPadding + (elHeight - newRect.height) / 2
} else if (flag === 2) {
newX = -newRect.x + fitPadding
newY = -newRect.y + fitPadding + (elHeight - newRect.height) / 2
} else if (flag === 3) {
newX = -newRect.x + fitPadding + (elWidth - newRect.width) / 2
newY = -newRect.y + fitPadding
}
this.translateXY(newX, newY)
}
}
export default View

View File

@@ -1,5 +1,5 @@
import Node from '../Node'
import { CONSTANTS, initRootNodePositionMap } from '../utils/constant'
import Node from '../core/render/node/Node'
import { CONSTANTS, initRootNodePositionMap } from '../constants/constant'
import Lru from '../utils/Lru'
// 布局基类

View File

@@ -1,6 +1,6 @@
import Base from './Base'
import { walk, asyncRun, degToRad } from '../utils'
import { CONSTANTS } from '../utils/constant'
import { CONSTANTS } from '../constants/constant'
import utils from './fishboneUtils'
// 鱼骨图

View File

@@ -1,6 +1,6 @@
import Base from './Base'
import { walk, asyncRun } from '../utils'
import { CONSTANTS } from '../utils/constant'
import { CONSTANTS } from '../constants/constant'
// 时间轴
class Timeline extends Base {

View File

@@ -1,4 +1,4 @@
import { walk, bfsWalk, throttle } from './utils/'
import { walk, bfsWalk, throttle } from '../utils'
import { v4 as uuid } from 'uuid'
import {
getAssociativeLineTargetIndex,
@@ -7,9 +7,9 @@ import {
getNodePoint,
computeNodePoints,
getNodeLinePath
} from './utils/associativeLineUtils'
import associativeLineControlsMethods from './utils/associativeLineControls'
import associativeLineTextMethods from './utils/associativeLineText'
} from './associativeLine/associativeLineUtils'
import associativeLineControlsMethods from './associativeLine/associativeLineControls'
import associativeLineTextMethods from './associativeLine/associativeLineText'
// 关联线类
class AssociativeLine {
@@ -91,12 +91,7 @@ class AssociativeLine {
this.mindMap.on('node_dragging', this.onNodeDragging.bind(this))
this.mindMap.on('node_dragend', this.onNodeDragend.bind(this))
// 拖拽控制点
window.addEventListener('mousemove', e => {
this.onControlPointMousemove(e)
})
window.addEventListener('mouseup', e => {
this.onControlPointMouseup(e)
})
this.mindMap.on('mouseup', this.onControlPointMouseup.bind(this))
// 缩放事件
this.mindMap.on('scale', this.onScale)
}
@@ -266,12 +261,13 @@ class AssociativeLine {
// 鼠标移动事件
onMousemove(e) {
if (!this.isCreatingLine) return
this.onControlPointMousemove(e)
this.updateCreatingLine(e)
}
// 更新创建过程中的连接线
updateCreatingLine(e) {
if (!this.isCreatingLine) return
let { x, y } = this.getTransformedEventPos(e)
let startPoint = getNodePoint(this.creatingStartNode)
let offsetX = x > startPoint.x ? -10 : 10

View File

@@ -1,5 +1,5 @@
import { bfsWalk, throttle } from './utils'
import Base from './layouts/Base'
import { bfsWalk, throttle } from '../utils'
import Base from '../layouts/Base'
// 节点拖动类

View File

@@ -1,9 +1,7 @@
import { imgToDataUrl, downloadFile, readBlob } from './utils'
import JsPDF from 'jspdf'
import { imgToDataUrl, downloadFile, readBlob } from '../utils'
import { SVG } from '@svgdotjs/svg.js'
import drawBackgroundImageToCanvas from './utils/simulateCSSBackgroundInCanvas'
import { transformToMarkdown } from './parse/toMarkdown'
const URL = window.URL || window.webkitURL || window
import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas'
import { transformToMarkdown } from '../parse/toMarkdown'
// 导出类
class Export {
@@ -175,34 +173,11 @@ class Export {
// 导出为pdf
async pdf(name) {
let img = await this.png()
let pdf = new JsPDF('', 'pt', 'a4')
let a4Width = 595
let a4Height = 841
let a4Ratio = a4Width / a4Height
let image = new Image()
image.onload = () => {
let imageWidth = image.width
let imageHeight = image.height
let imageRatio = imageWidth / imageHeight
let w, h
if (imageWidth <= a4Width && imageHeight <= a4Height) {
// 使用图片原始宽高
w = imageWidth
h = imageHeight
} else if (a4Ratio > imageRatio) {
// 以a4Height为高度缩放图片宽度
w = imageRatio * a4Height
h = a4Height
} else {
// 以a4Width为宽度缩放图片高度
w = a4Width
h = a4Width / imageRatio
}
pdf.addImage(img, 'PNG', (a4Width - w) / 2, (a4Height - h) / 2, w, h)
pdf.save(name)
if (!this.mindMap.doExportPDF) {
throw new Error('请注册ExportPDF插件')
}
image.src = img
let img = await this.png()
this.mindMap.doExportPDF.pdf(name, img)
}
// 导出为svg

View File

@@ -0,0 +1,44 @@
import JsPDF from 'jspdf'
// 导出PDF类需要通过Export插件使用
class ExportPDF {
// 构造函数
constructor(opt) {
this.mindMap = opt.mindMap
}
// 导出为pdf
pdf(name, img) {
let pdf = new JsPDF('', 'pt', 'a4')
let a4Width = 595
let a4Height = 841
let a4Ratio = a4Width / a4Height
let image = new Image()
image.onload = () => {
let imageWidth = image.width
let imageHeight = image.height
let imageRatio = imageWidth / imageHeight
let w, h
if (imageWidth <= a4Width && imageHeight <= a4Height) {
// 使用图片原始宽高
w = imageWidth
h = imageHeight
} else if (a4Ratio > imageRatio) {
// 以a4Height为高度缩放图片宽度
w = imageRatio * a4Height
h = a4Height
} else {
// 以a4Width为宽度缩放图片高度
w = a4Width
h = a4Width / imageRatio
}
pdf.addImage(img, 'PNG', (a4Width - w) / 2, (a4Height - h) / 2, w, h)
pdf.save(name)
}
image.src = img
}
}
ExportPDF.instanceName = 'doExportPDF'
export default ExportPDF

View File

@@ -1,5 +1,5 @@
import { bfsWalk } from './utils'
import { CONSTANTS } from './utils/constant'
import { bfsWalk } from '../utils'
import { CONSTANTS } from '../constants/constant'
// 键盘导航类
class KeyboardNavigation {

View File

@@ -1,8 +1,8 @@
import Quill from 'quill'
import 'quill/dist/quill.snow.css'
import html2canvas from 'html2canvas'
import { walk, getTextFromHtml } from './utils'
import { CONSTANTS } from './utils/constant'
import { walk, getTextFromHtml } from '../utils'
import { CONSTANTS } from '../constants/constant'
let extended = false
@@ -41,9 +41,12 @@ class RichText {
this.node = null
this.styleEl = null
this.cacheEditingText = ''
this.lostStyle = false
this.isCompositing = false
this.initOpt()
this.extendQuill()
this.appendCss()
this.bindEvent()
// 处理数据,转成富文本格式
if (this.mindMap.opt.data) {
@@ -51,6 +54,20 @@ class RichText {
}
}
// 绑定事件
bindEvent() {
this.onCompositionStart = this.onCompositionStart.bind(this)
this.onCompositionEnd = this.onCompositionEnd.bind(this)
window.addEventListener('compositionstart', this.onCompositionStart)
window.addEventListener('compositionend', this.onCompositionEnd)
}
// 解绑事件
unbindEvent() {
window.removeEventListener('compositionstart', this.onCompositionStart)
window.removeEventListener('compositionend', this.onCompositionEnd)
}
// 插入样式
appendCss() {
let cssText = `
@@ -59,6 +76,7 @@ class RichText {
padding: 0;
height: auto;
line-height: normal;
-webkit-user-select: text;
}
.ql-container {
@@ -159,13 +177,15 @@ class RichText {
this.textEditNode.style.marginLeft = `-${paddingX * scaleX}px`
this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
this.textEditNode.style.backgroundColor = bgColor === 'transparent' ? '#fff' : bgColor
this.textEditNode.style.backgroundColor =
bgColor === 'transparent' ? '#fff' : bgColor
this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
this.textEditNode.style.minHeight = originHeight + 'px'
this.textEditNode.style.left = rect.left + 'px'
this.textEditNode.style.top = rect.top + 'px'
this.textEditNode.style.display = 'block'
this.textEditNode.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + paddingX * 2 + 'px'
this.textEditNode.style.maxWidth =
this.mindMap.opt.textAutoWrapWidth + paddingX * 2 + 'px'
this.textEditNode.style.transform = `scale(${scaleX}, ${scaleY})`
this.textEditNode.style.transformOrigin = 'left top'
if (!node.nodeData.data.richText) {
@@ -174,7 +194,8 @@ class RichText {
let html = `<p>${text}</p>`
this.textEditNode.innerHTML = this.cacheEditingText || html
} else {
this.textEditNode.innerHTML = this.cacheEditingText || node.nodeData.data.text
this.textEditNode.innerHTML =
this.cacheEditingText || node.nodeData.data.text
}
this.initQuillEditor()
document.querySelector('.ql-editor').style.minHeight = originHeight + 'px'
@@ -198,7 +219,7 @@ class RichText {
underline: node.style.merge('textDecoration') === 'underline',
strike: node.style.merge('textDecoration') === 'line-through'
}
this.formatAllText(style)
this.pureFormatAllText(style)
}
// 获取当前正在编辑的内容
@@ -214,7 +235,8 @@ class RichText {
return
}
let html = this.getEditText()
let list = nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
let list =
nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
list.forEach(node => {
this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
if (node.isGeneralization) {
@@ -223,11 +245,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.textEditNode.style.display = 'none'
this.showTextEdit = false
this.mindMap.emit('rich_text_selection_change', false)
@@ -281,6 +299,37 @@ class RichText {
)
}
})
this.quill.on('text-change', () => {
let contents = this.quill.getContents()
let len = contents.ops.length
// 如果编辑过程中删除所有字符,那么会丢失主题的样式
if (len <= 0 || (len === 1 && contents.ops[0].insert === '\n')) {
this.lostStyle = true
// 需要删除节点的样式数据
this.syncFormatToNodeConfig(null, true)
} else if (this.lostStyle && !this.isCompositing) {
// 如果处于样式丢失状态,那么需要进行格式化加回样式
this.setTextStyleIfNotRichText(this.node)
this.lostStyle = false
}
})
}
// 正则输入中文
onCompositionStart() {
if (!this.showTextEdit) {
return
}
this.isCompositing = true
}
// 中文输入结束
onCompositionEnd() {
if (!this.showTextEdit || !this.lostStyle) {
return
}
this.isCompositing = false
this.setTextStyleIfNotRichText(this.node)
}
// 选中全部
@@ -300,7 +349,9 @@ class RichText {
this.syncFormatToNodeConfig(config, clear)
let rangeLost = !this.range
let range = rangeLost ? this.lastRange : this.range
clear ? this.quill.removeFormat(range.index, range.length) : this.quill.formatText(range.index, range.length, config)
clear
? this.quill.removeFormat(range.index, range.length)
: this.quill.formatText(range.index, range.length, config)
if (rangeLost) {
this.quill.setSelection(this.lastRange.index, this.lastRange.length)
}
@@ -321,6 +372,11 @@ class RichText {
// 格式化所有文本
formatAllText(config = {}) {
this.syncFormatToNodeConfig(config)
this.pureFormatAllText(config)
}
// 纯粹的格式化所有文本
pureFormatAllText(config = {}) {
this.quill.formatText(0, this.quill.getLength(), config)
}
@@ -329,7 +385,14 @@ class RichText {
if (!this.node) return
if (clear) {
// 清除文本样式
['fontFamily', 'fontSize', 'fontWeight', 'fontStyle', 'textDecoration', 'color'].forEach((prop) => {
;[
'fontFamily',
'fontSize',
'fontWeight',
'fontStyle',
'textDecoration',
'color'
].forEach(prop => {
delete this.node.nodeData.data[prop]
})
} else {
@@ -412,11 +475,11 @@ class RichText {
el.appendChild(node)
this.mindMap.el.appendChild(el)
// 遍历所有节点将它们的margin和padding设为0
let walk = (root) => {
let walk = root => {
root.style.margin = 0
root.style.padding = 0
if (root.hasChildNodes()) {
Array.from(root.children).forEach((item) => {
Array.from(root.children).forEach(item => {
walk(item)
})
}
@@ -454,13 +517,13 @@ class RichText {
// 处理导入数据
handleSetData(data) {
let walk = (root) => {
let walk = root => {
if (!root.data.richText) {
root.data.richText = true
root.data.resetRichText = true
}
if (root.children && root.children.length > 0) {
Array.from(root.children).forEach((item) => {
Array.from(root.children).forEach(item => {
walk(item)
})
}

View File

@@ -1,4 +1,4 @@
import { bfsWalk, throttle } from './utils'
import { bfsWalk, throttle } from '../utils'
// 选择节点类
@@ -22,9 +22,14 @@ class Select {
if (this.mindMap.opt.readonly) {
return
}
if (!e.ctrlKey && e.which !== 3) {
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
if (
!e.ctrlKey &&
(useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3)
) {
return
}
e.preventDefault()
this.isMousedown = true
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x
@@ -146,25 +151,24 @@ class Select {
let bottom = (top + height) * scaleY + translateY
left = left * scaleX + translateX
top = top * scaleY + translateY
if ((left >= minx && left <= maxx ||
right >= minx && right <= maxx) &&
(top >= miny && top <= maxy ||
bottom >= miny && bottom <= maxy)
) {
if (
((left >= minx && left <= maxx) || (right >= minx && right <= maxx)) &&
((top >= miny && top <= maxy) || (bottom >= miny && bottom <= maxy))
) {
// this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
if (node.nodeData.data.isActive) {
return
}
this.mindMap.renderer.setNodeActive(node, true)
this.mindMap.renderer.addActiveNode(node)
if (node.nodeData.data.isActive) {
return
}
this.mindMap.renderer.setNodeActive(node, true)
this.mindMap.renderer.addActiveNode(node)
// })
} else if (node.nodeData.data.isActive) {
// this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
if (!node.nodeData.data.isActive) {
return
}
this.mindMap.renderer.setNodeActive(node, false)
this.mindMap.renderer.removeActiveNode(node)
if (!node.nodeData.data.isActive) {
return
}
this.mindMap.renderer.setNodeActive(node, false)
this.mindMap.renderer.removeActiveNode(node)
// })
}
})

View File

@@ -0,0 +1,126 @@
// 手势事件支持类
class TouchEvent {
// 构造函数
constructor({ mindMap }) {
this.mindMap = mindMap
this.touchesNum = 0
this.singleTouchstartEvent = null
this.clickNum = 0
this.doubleTouchmoveDistance = 0
this.bindEvent()
}
// 绑定事件
bindEvent() {
this.onTouchstart = this.onTouchstart.bind(this)
this.onTouchmove = this.onTouchmove.bind(this)
this.onTouchcancel = this.onTouchcancel.bind(this)
this.onTouchend = this.onTouchend.bind(this)
window.addEventListener('touchstart', this.onTouchstart)
window.addEventListener('touchmove', this.onTouchmove)
window.addEventListener('touchcancel', this.onTouchcancel)
window.addEventListener('touchend', this.onTouchend)
}
// 解绑事件
unBindEvent() {
window.removeEventListener('touchstart', this.onTouchstart)
window.removeEventListener('touchmove', this.onTouchmove)
window.removeEventListener('touchcancel', this.onTouchcancel)
window.removeEventListener('touchend', this.onTouchend)
}
// 手指按下事件
onTouchstart(e) {
this.touchesNum = e.touches.length
if (this.touchesNum === 1) {
let touch = e.touches[0]
this.singleTouchstartEvent = touch
this.dispatchMouseEvent('mousedown', touch.target, touch)
}
}
// 手指移动事件
onTouchmove(e) {
let len = e.touches.length
if (len === 1) {
let touch = e.touches[0]
this.dispatchMouseEvent('mousemove', touch.target, touch)
} else if (len === 2) {
let touch1 = e.touches[0]
let touch2 = e.touches[1]
let ox = touch1.clientX - touch2.clientX
let oy = touch1.clientY - touch2.clientY
let distance = Math.sqrt(Math.pow(ox, 2) + Math.pow(oy, 2))
// 以两指中心点进行缩放
let { x: touch1ClientX, y: touch1ClientY } = this.mindMap.toPos(touch1.clientX, touch1.clientY)
let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(touch2.clientX, touch2.clientY)
let cx = (touch1ClientX + touch2ClientX) / 2
let cy = (touch1ClientY + touch2ClientY) / 2
if (distance > this.doubleTouchmoveDistance) {
// 放大
this.mindMap.view.enlarge(cx, cy)
} else {
// 缩小
this.mindMap.view.narrow(cx, cy)
}
this.doubleTouchmoveDistance = distance
}
}
// 手指取消事件
onTouchcancel(e) {}
// 手指松开事件
onTouchend(e) {
this.dispatchMouseEvent('mouseup', e.target)
if (this.touchesNum === 1) {
// 模拟双击事件
this.clickNum++
setTimeout(() => {
this.clickNum = 0
}, 300)
let ev = this.singleTouchstartEvent
if (this.clickNum > 1) {
this.clickNum = 0
this.dispatchMouseEvent('dblclick', ev.target, ev)
} else {
this.dispatchMouseEvent('click', ev.target, ev)
}
}
this.touchesNum = 0
this.singleTouchstartEvent = null
this.doubleTouchmoveDistance = 0
}
// 发送鼠标事件
dispatchMouseEvent(eventName, target, e) {
let opt = {}
if (e) {
opt = {
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY,
which: 1
}
}
let event = new MouseEvent(eventName, {
view: window,
bubbles: true,
cancelable: true,
...opt
})
target.dispatchEvent(event)
}
// 插件被移除前做的事情
beforePluginRemove() {
this.unBindEvent()
}
}
TouchEvent.instanceName = 'touchEvent'
export default TouchEvent

View File

@@ -1,5 +1,5 @@
import { Text, G } from '@svgdotjs/svg.js'
import { degToRad, camelCaseToHyphen } from './utils'
import { degToRad, camelCaseToHyphen } from '../utils'
import merge from 'deepmerge'
// 水印类

View File

@@ -1,5 +1,5 @@
import { Text } from '@svgdotjs/svg.js'
import { getStrWithBrFromHtml } from './index'
import { getStrWithBrFromHtml } from '../../utils/index'
// 创建文字节点
function createText(data) {

View File

@@ -1,4 +1,4 @@
import { nextTick } from './utils'
import { nextTick } from '.'
// 批量执行
class BatchExecution {

View File

@@ -356,4 +356,15 @@ export const readBlob = (blob) => {
}
reader.readAsDataURL(blob)
})
}
// 将dom节点转换成html字符串
let nodeToHTMLWrapEl = null
export const nodeToHTML = (node) => {
if (!nodeToHTMLWrapEl) {
nodeToHTMLWrapEl = document.createElement('div')
}
nodeToHTMLWrapEl.innerHTML = ''
nodeToHTMLWrapEl.appendChild(node)
return nodeToHTMLWrapEl.innerHTML
}

55
web/package-lock.json generated
View File

@@ -33,6 +33,7 @@
"markdown-it": "^13.0.1",
"markdown-it-checkbox": "^1.1.0",
"prettier": "^1.19.1",
"vconsole": "^3.15.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.44.2"
}
@@ -5168,6 +5169,18 @@
"node": ">=0.10.0"
}
},
"node_modules/copy-text-to-clipboard": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz",
"integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/copy-webpack-plugin": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
@@ -10351,6 +10364,12 @@
"integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==",
"dev": true
},
"node_modules/mutation-observer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz",
"integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==",
"dev": true
},
"node_modules/mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -15185,6 +15204,18 @@
"node": ">= 0.8"
}
},
"node_modules/vconsole": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.15.1.tgz",
"integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.17.2",
"copy-text-to-clipboard": "^3.0.1",
"core-js": "^3.11.0",
"mutation-observer": "^1.0.3"
}
},
"node_modules/vendors": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
@@ -20525,6 +20556,12 @@
"integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
"dev": true
},
"copy-text-to-clipboard": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz",
"integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==",
"dev": true
},
"copy-webpack-plugin": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
@@ -24567,6 +24604,12 @@
"integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==",
"dev": true
},
"mutation-observer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz",
"integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==",
"dev": true
},
"mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -28566,6 +28609,18 @@
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true
},
"vconsole": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.15.1.tgz",
"integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
"dev": true,
"requires": {
"@babel/runtime": "^7.17.2",
"copy-text-to-clipboard": "^3.0.1",
"core-js": "^3.11.0",
"mutation-observer": "^1.0.3"
}
},
"vendors": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",

View File

@@ -37,6 +37,7 @@
"markdown-it": "^13.0.1",
"markdown-it-checkbox": "^1.1.0",
"prettier": "^1.19.1",
"vconsole": "^3.15.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.44.2"
},

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<link rel="icon" href="./dist/logo.png">
<title>一个简单的web思维导图实现</title>
</head>

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2479351 */
src: url('iconfont.woff2?t=1679621707211') format('woff2'),
url('iconfont.woff?t=1679621707211') format('woff'),
url('iconfont.ttf?t=1679621707211') format('truetype');
src: url('iconfont.woff2?t=1686298427624') format('woff2'),
url('iconfont.woff?t=1686298427624') format('woff'),
url('iconfont.ttf?t=1686298427624') format('truetype');
}
.iconfont {
@@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.iconmouseR:before {
content: "\e6bd";
}
.iconmouseL:before {
content: "\e6c0";
}
.iconwenjian:before {
content: "\e607";
}

View File

@@ -291,6 +291,11 @@ export const shortcutKeyList = [
icon: 'icondingwei',
name: 'Reset',
value: 'Ctrl + Enter'
},
{
icon: 'iconquanping1',
name: 'fit canvas',
value: 'Ctrl + i'
}
]
}

View File

@@ -351,6 +351,11 @@ export const shortcutKeyList = [
icon: 'icondingwei',
name: '恢复默认',
value: 'Ctrl + Enter'
},
{
icon: 'iconquanping1',
name: '适应画布',
value: 'Ctrl + i'
}
]
}

View File

@@ -69,7 +69,8 @@ export default {
level4: 'Level4',
level5: 'Level5',
level6: 'Level6',
zenMode: 'Zen mode'
zenMode: 'Zen mode',
fitCanvas: 'Fit canvas'
},
count: {
words: 'Words',
@@ -201,5 +202,9 @@ export default {
edit: {
newFeatureNoticeTitle: 'New feature reminder',
newFeatureNoticeMessage: 'This update supports node rich text editing, But there are some defects, The most important impact is that the time to export the image is proportional to the number of nodes, Therefore, if you are more dependent on export requirements, you can use【Base style】-【Other config】-【Enable node rich text editing】Set to turn off rich text editing mode.'
},
mouseAction: {
tip1: 'Current: Left click to drag the canvas, right click to box select nodes',
tip2: 'Current: Left click to box select nodes, right click to drag the canvas',
}
}

View File

@@ -69,7 +69,8 @@ export default {
level4: '四级主题',
level5: '五级主题',
level6: '六级主题',
zenMode: '禅模式'
zenMode: '禅模式',
fitCanvas: '适应画布'
},
count: {
words: '字数',
@@ -201,5 +202,9 @@ export default {
edit: {
newFeatureNoticeTitle: '新特性提醒',
newFeatureNoticeMessage: '本次更新支持了节点富文本编辑,但是存在一定缺陷,最主要的影响是导出为图片的时间和节点数量成正比,所以对导出需求比较依赖的话可以通过【基础样式】-【其他配置】-【是否开启节点富文本编辑】设置关掉富文本编辑模式。'
},
mouseAction: {
tip1: '当前:左键拖动画布,右键框选节点',
tip2: '当前:左键框选节点,右键拖动画布',
}
}

View File

@@ -8,6 +8,8 @@ import '@/assets/icon-font/iconfont.css'
import 'viewerjs/dist/viewer.css'
import VueViewer from 'v-viewer'
import i18n from './i18n'
// import VConsole from 'vconsole'
// const vConsole = new VConsole()
Vue.config.productionTip = false
Vue.prototype.$bus = new Vue()

View File

@@ -11,7 +11,7 @@ let langList = [
}
]
let StartList = ['introduction', 'start', 'deploy', 'client', 'translate', 'changelog']
let CourseList = new Array(19).fill(0).map((_, index) => {
let CourseList = new Array(20).fill(0).map((_, index) => {
return 'course' + (index + 1)
})
let APIList = [
@@ -30,6 +30,7 @@ let APIList = [
'miniMap',
'watermark',
'associativeLine',
'touchEvent',
'xmind',
'markdown',
'utils'

View File

@@ -12,7 +12,8 @@ This plugin is used to support the addition of associative lines.
```js
import MindMap from 'simple-mind-map'
import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
// import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js' Use this path for versions below v0.6.0
MindMap.usePlugin(AssociativeLine)
```

View File

@@ -13,7 +13,8 @@
<p>This plugin is used to support the addition of associative lines.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/AssociativeLine.js&#x27;</span>
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/AssociativeLine.js&#x27;</span>
<span class="hljs-comment">// import AssociativeLine from &#x27;simple-mind-map/src/AssociativeLine.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(AssociativeLine)
</code></pre>

View File

@@ -1,5 +1,41 @@
# Changelog
## 0.6.4-fix.1
New: 1.When zooming with the mouse wheel, the default zoom is centered around the current position of the mouse, which can be turned off by configuring.
Fix: 1.Fixed an issue where the default value of the zoom center point was not updated after changing the canvas size.
## 0.6.4
New: 1.The default is to scale at the center point of the canvas. 2.Optimize the scaling of both fingers on the mobile end, with the center position of the two fingers as the center point for scaling.
## 0.6.3
Fix: 1.Fix the issue where the summary node will respond to inserting node shortcuts.
New: 1.Support custom node content.
## 0.6.2
Fix: 1.Fixed the problem that the new node does not change with the theme in rich Text mode.
## 0.6.1
Fix: 1.Fixed the issue of high movement sensitivity when using the touchpad when changing mouse scrolling to moving the canvas behavior.
## 0.6.0-fix.1
Fix: 1.Fixed the issue of destroying mind maps without setting a background style and reporting errors.
## 0.6.0
Breaking change: Adjusted the directory structure of the simple-mind-map source code, Main impact: 1. The introduction path of the plugin needs to be modified. The constant file path needs to be modified.
New: 1.Supports one click zoom to fit the canvas function. 2.Press and hold the Ctrl key to activate the multi selection function on demand through configuration. 3.Support setting to left click to select multiple nodes and right click to drag the canvas. 4. Support controlling whether nodes are allowed to be edited. 5.Add a method for destroying mind maps. 6.Added touch event support plugin.
Fix: 1.Fix the issue where holding down the Ctrl key to select multiple nodes does not trigger the click event for the node. 2.Fixed the issue of node style loss when clearing a node and then entering text.
## 0.5.11
New: Supports associative text editing.

View File

@@ -1,6 +1,24 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.6.4-fix.1</h2>
<p>New: 1.When zooming with the mouse wheel, the default zoom is centered around the current position of the mouse, which can be turned off by configuring.</p>
<p>Fix: 1.Fixed an issue where the default value of the zoom center point was not updated after changing the canvas size.</p>
<h2>0.6.4</h2>
<p>New: 1.The default is to scale at the center point of the canvas. 2.Optimize the scaling of both fingers on the mobile end, with the center position of the two fingers as the center point for scaling.</p>
<h2>0.6.3</h2>
<p>Fix: 1.Fix the issue where the summary node will respond to inserting node shortcuts.</p>
<p>New: 1.Support custom node content.</p>
<h2>0.6.2</h2>
<p>Fix: 1.Fixed the problem that the new node does not change with the theme in rich Text mode.</p>
<h2>0.6.1</h2>
<p>Fix: 1.Fixed the issue of high movement sensitivity when using the touchpad when changing mouse scrolling to moving the canvas behavior.</p>
<h2>0.6.0-fix.1</h2>
<p>Fix: 1.Fixed the issue of destroying mind maps without setting a background style and reporting errors.</p>
<h2>0.6.0</h2>
<p>Breaking change: Adjusted the directory structure of the simple-mind-map source code, Main impact: 1. The introduction path of the plugin needs to be modified. The constant file path needs to be modified.</p>
<p>New: 1.Supports one click zoom to fit the canvas function. 2.Press and hold the Ctrl key to activate the multi selection function on demand through configuration. 3.Support setting to left click to select multiple nodes and right click to drag the canvas. 4. Support controlling whether nodes are allowed to be edited. 5.Add a method for destroying mind maps. 6.Added touch event support plugin.</p>
<p>Fix: 1.Fix the issue where holding down the Ctrl key to select multiple nodes does not trigger the click event for the node. 2.Fixed the issue of node style loss when clearing a node and then entering text.</p>
<h2>0.5.11</h2>
<p>New: Supports associative text editing.</p>
<p>optimization: Optimizing theme configuration updates, changing configurations that do not involve node size does not trigger node recalculation.</p>

View File

@@ -25,11 +25,11 @@ const mindMap = new MindMap({
| Field Name | Type | Default Value | Description | Required |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ | -------- |
| el | Element | | Container element, must be a DOM element | Yes |
| data | Object | {} | Mind map data, refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js | |
| data | Object | {} | Mind map data, refer to: [exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) | |
| layout | String | logicalStructure | Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)、timelinev0.5.4+, timeline、timeline2v0.5.4+, up down alternating timeline、fishbonev0.5.4+, fishbone diagram | |
| fishboneDegv0.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: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js | |
| themeConfig | Object | {} | Theme configuration, will be merged with the selected theme, available fields refer to: [default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
| scaleRatio | Number | 0.1 | The incremental scaling ratio | |
| maxTag | Number | 5 | The maximum number of tags displayed in the node, any additional tags will be discarded | |
| exportPadding | Number | 20 | The padding for exporting images | |
@@ -62,6 +62,14 @@ const mindMap = new MindMap({
| alwaysShowExpandBtnv0.5.8+ | Boolean | false | Whether to always display the expand and collapse buttons of nodes, which are only displayed when the mouse is moved up and activated by default | |
| iconListv0.5.8+ | Array | [] | The icons that can be inserted into the extension node, and each item in the array is an object. Please refer to the "Icon Configuration" table below for the detailed structure of the object | |
| maxNodeCacheCountv0.5.10+ | Number | 1000 | The maximum number of cached nodes. To optimize performance, an internal node cache pool is maintained to reuse nodes. This attribute allows you to specify the maximum number of caches in the pool | |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | Association Line Default Text | |
| fitPaddingv0.6.0+ | Number | 50 | The padding of mind mapping when adapting to canvas size, Unit: px | |
| enableCtrlKeyNodeSelectionv0.6.0+ | Boolean | true | Whether to enable the function of holding down the Ctrl key to select multiple nodes | |
| useLeftKeySelectionRightKeyDragv0.6.0+ | Boolean | false | Setting to left click to select multiple nodes and right click to drag the canvas. | |
| beforeTextEditv0.6.0+ | Function/null | null | The callback method before the node is about to enter editing. If the method returns a value other than true, the editing will be canceled. The function can return a value or a promise, and the callback parameter is the node instance | |
| isUseCustomNodeContentv0.6.3+ | Boolean | false | Whether to customize node content | |
| customCreateNodeContentv0.6.3+ | Function/null | null | If `isUseCustomNodeContent` is set to `true`, then this option needs to be used to pass in a method that receives the node instance `node` as a parameter (if you want to obtain data for that node, you can use `node.nodeData.data`). You need to return the custom node content element, which is the DOM node. If a node does not require customization, you can return `null` | |
| mouseScaleCenterUseMousePositionv0.6.4-fix.1+ | Boolean | true | Is the mouse zoom centered around the current position of the mouse, otherwise centered around the canvas | |
### Watermark config
@@ -140,6 +148,12 @@ List of all currently registered plugins.
## Instance methods
### destroy()
> v0.6.0+
Destroy mind maps. It will remove registered plugins, remove listening events, and delete all nodes on the canvas.
### getSvgData({ paddingX = 0, paddingY = 0 })
> v0.3.0+
@@ -203,7 +217,7 @@ Listen to an event. Event list:
| mousemove | el element mouse move event | e (event object), this (Event event class instance) |
| drag | If it is a drag event while holding down the left button | e (event object), this (Event event class instance) |
| mouseup | el element mouse up event | e (event object), this (Event event class instance) |
| mousewheel | Mouse scroll event | e (event object), dir (up or down scroll), this (Event event class instance) |
| mousewheel | Mouse scroll event | e (event object), dir (up or down scroll), this (Event event class instance) 、isTouchPadv0.6.1+, Is it an event triggered by the touchpad |
| contextmenu | svg canvas right mouse button menu event | e (event object) |
| node_click | Node click event | this (node instance), e (event object) |
| node_mousedown | Node mouse down event | this (node instance), e (event object) |
@@ -301,8 +315,8 @@ redo. All commands are as follows:
| SELECT_ALL | Select all | |
| BACK | Go back a specified number of steps | step (the number of steps to go back, default is 1) |
| FORWARD | Go forward a specified number of steps | step (the number of steps to go forward, default is 1) |
| INSERT_NODE | Insert a sibling node, the active node or appoint node will be the operation node. If there are multiple active nodes, only the first one will be effective | openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is `true` 、 appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array、 appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_CHILD_NODE | Insert a child node, the active node or appoint node will be the operation node | openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is `true`)、 appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array、 appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_NODE | Insert a sibling node, the active node or appoint node will be the operation node. If there are multiple active nodes, only the first one will be effective | openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is `true` 、 appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array、 appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to [exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_CHILD_NODE | Insert a child node, the active node or appoint node will be the operation node | openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is `true`)、 appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array、 appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to [exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| UP_NODE | Move node up, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the first node in the list will be invalid | |
| DOWN_NODE | Move node down, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the last node in the list will be invalid | |
| REMOVE_NODE | Remove node, the active node or appoint node will be the operation node | appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array |
@@ -317,10 +331,10 @@ redo. All commands are as follows:
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
| SET_NODE_TEXT | Set node text | node (the node to set), text (the new text for the node), richTextv0.4.0+, If you want to set a rich text character, you need to set it to `true` |
| SET_NODE_IMAGE | Set Node Image | node (node to set), imgData (object, image information, structured as: `{url, title, width, height}`, the width and height of the image must be passed) |
| SET_NODE_ICON | Set Node Icon | node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js) file, icon name is type_name, such as ['priority_1']) |
| SET_NODE_ICON | Set Node Icon | node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the [icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js) file, icon name is type_name, such as ['priority_1']) |
| SET_NODE_HYPERLINK | Set Node Hyperlink | node (node to set), link (hyperlink address), title (hyperlink name, optional) |
| SET_NODE_NOTE | Set Node Note | node (node to set), note (note text) |
| SET_NODE_TAG | Set Node Tag | node (node to set), tag (string array, built-in color information can be obtained in [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js)) |
| SET_NODE_TAG | Set Node Tag | node (node to set), tag (string array, built-in color information can be obtained in [constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/constants/constant.js)) |
| INSERT_AFTER (v0.1.5+) | Move Node to After Another Node | node (node to move), exist (target node) |
| INSERT_BEFORE (v0.1.5+) | Move Node to Before Another Node | node (node to move), exist (target node) |
| MOVE_NODE_TO (v0.1.5+) | Move a node as a child of another node | node (the node to move), toNode (the target node) |
@@ -328,7 +342,7 @@ redo. All commands are as follows:
| REMOVE_GENERALIZATION (v0.2.0+) | Remove a node summary | |
| SET_NODE_CUSTOM_POSITION (v0.2.0+) | Set a custom position for a node | node (the node to set), left (custom x coordinate, default is undefined), top (custom y coordinate, default is undefined) |
| RESET_LAYOUT (v0.2.0+) | Arrange layout with one click | |
| SET_NODE_SHAPE (v0.2.4+) | Set the shape of a node | node (the node to set), shape (the shape, all shapes: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
| SET_NODE_SHAPE (v0.2.4+) | Set the shape of a node | node (the node to set), shape (the shape, all shapes: [Shape.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/render/node/Shape.js)) |
### setData(data)

View File

@@ -39,7 +39,7 @@
<td>data</td>
<td>Object</td>
<td>{}</td>
<td>Mind map data, refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</td>
<td>Mind map data, refer to: <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a></td>
<td></td>
</tr>
<tr>
@@ -67,7 +67,7 @@
<td>themeConfig</td>
<td>Object</td>
<td>{}</td>
<td>Theme configuration, will be merged with the selected theme, available fields refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js</td>
<td>Theme configuration, will be merged with the selected theme, available fields refer to: <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">default.js</a></td>
<td></td>
</tr>
<tr>
@@ -294,6 +294,62 @@
<td>The maximum number of cached nodes. To optimize performance, an internal node cache pool is maintained to reuse nodes. This attribute allows you to specify the maximum number of caches in the pool</td>
<td></td>
</tr>
<tr>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td>关联</td>
<td>Association Line Default Text</td>
<td></td>
</tr>
<tr>
<td>fitPaddingv0.6.0+</td>
<td>Number</td>
<td>50</td>
<td>The padding of mind mapping when adapting to canvas size, Unit: px</td>
<td></td>
</tr>
<tr>
<td>enableCtrlKeyNodeSelectionv0.6.0+</td>
<td>Boolean</td>
<td>true</td>
<td>Whether to enable the function of holding down the Ctrl key to select multiple nodes</td>
<td></td>
</tr>
<tr>
<td>useLeftKeySelectionRightKeyDragv0.6.0+</td>
<td>Boolean</td>
<td>false</td>
<td>Setting to left click to select multiple nodes and right click to drag the canvas.</td>
<td></td>
</tr>
<tr>
<td>beforeTextEditv0.6.0+</td>
<td>Function/null</td>
<td>null</td>
<td>The callback method before the node is about to enter editing. If the method returns a value other than true, the editing will be canceled. The function can return a value or a promise, and the callback parameter is the node instance</td>
<td></td>
</tr>
<tr>
<td>isUseCustomNodeContentv0.6.3+</td>
<td>Boolean</td>
<td>false</td>
<td>Whether to customize node content</td>
<td></td>
</tr>
<tr>
<td>customCreateNodeContentv0.6.3+</td>
<td>Function/null</td>
<td>null</td>
<td>If <code>isUseCustomNodeContent</code> is set to <code>true</code>, then this option needs to be used to pass in a method that receives the node instance <code>node</code> as a parameter (if you want to obtain data for that node, you can use <code>node.nodeData.data</code>). You need to return the custom node content element, which is the DOM node. If a node does not require customization, you can return <code>null</code></td>
<td></td>
</tr>
<tr>
<td>mouseScaleCenterUseMousePositionv0.6.4-fix.1+</td>
<td>Boolean</td>
<td>true</td>
<td>Is the mouse zoom centered around the current position of the mouse, otherwise centered around the canvas</td>
<td></td>
</tr>
</tbody>
</table>
<h3>Watermark config</h3>
@@ -413,6 +469,11 @@ mindMap.setTheme(<span class="hljs-string">&#x27;Theme name&#x27;</span>)
</blockquote>
<p>List of all currently registered plugins.</p>
<h2>Instance methods</h2>
<h3>destroy()</h3>
<blockquote>
<p>v0.6.0+</p>
</blockquote>
<p>Destroy mind maps. It will remove registered plugins, remove listening events, and delete all nodes on the canvas.</p>
<h3>getSvgData({ paddingX = 0, paddingY = 0 })</h3>
<blockquote>
<p>v0.3.0+</p>
@@ -509,7 +570,7 @@ poor performance and should be used sparingly.</p>
<tr>
<td>mousewheel</td>
<td>Mouse scroll event</td>
<td>e (event object), dir (up or down scroll), this (Event event class instance)</td>
<td>e (event object), dir (up or down scroll), this (Event event class instance) isTouchPadv0.6.1+, Is it an event triggered by the touchpad</td>
</tr>
<tr>
<td>contextmenu</td>
@@ -700,12 +761,12 @@ redo. All commands are as follows:</p>
<tr>
<td>INSERT_NODE</td>
<td>Insert a sibling node, the active node or appoint node will be the operation node. If there are multiple active nodes, only the first one will be effective</td>
<td>openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is <code>true</code> appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a> </td>
<td>openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is <code>true</code> appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a> </td>
</tr>
<tr>
<td>INSERT_CHILD_NODE</td>
<td>Insert a child node, the active node or appoint node will be the operation node</td>
<td>openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is <code>true</code> appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a> </td>
<td>openEditv0.4.6+, Whether to activate the newly inserted node and enter editing mode, default is <code>true</code> appointNodesv0.4.7+, Optional, appoint node, Specifying multiple nodes can pass an array appointDataOptional, Specify the data for the newly created node, Such as {text: 'xxx', ...}, Detailed structure can be referred to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a> </td>
</tr>
<tr>
<td>UP_NODE</td>
@@ -780,7 +841,7 @@ redo. All commands are as follows:</p>
<tr>
<td>SET_NODE_ICON</td>
<td>Set Node Icon</td>
<td>node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js</a> file, icon name is type_name, such as ['priority_1'])</td>
<td>node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">icons.js</a> file, icon name is type_name, such as ['priority_1'])</td>
</tr>
<tr>
<td>SET_NODE_HYPERLINK</td>
@@ -795,7 +856,7 @@ redo. All commands are as follows:</p>
<tr>
<td>SET_NODE_TAG</td>
<td>Set Node Tag</td>
<td>node (node to set), tag (string array, built-in color information can be obtained in <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js</a>)</td>
<td>node (node to set), tag (string array, built-in color information can be obtained in <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/constants/constant.js">constant.js</a>)</td>
</tr>
<tr>
<td>INSERT_AFTER (v0.1.5+)</td>
@@ -835,7 +896,7 @@ redo. All commands are as follows:</p>
<tr>
<td>SET_NODE_SHAPE (v0.2.4+)</td>
<td>Set the shape of a node</td>
<td>node (the node to set), shape (the shape, all shapes: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js)</td>
<td>node (the node to set), shape (the shape, all shapes: <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/render/node/Shape.js">Shape.js</a>)</td>
</tr>
</tbody>
</table>

View File

@@ -6,7 +6,8 @@ The `Export` plugin provides the export function.
```js
import MindMap from 'simple-mind-map'
import Export from 'simple-mind-map/src/Export.js'
import Export from 'simple-mind-map/src/plugins/Export.js'
// import Export from 'simple-mind-map/src/Export.js' Use this path for versions below v0.6.0
MindMap.usePlugin(Export)
```
@@ -73,6 +74,13 @@ Exports as `svg`.
Export as `pdf`. Unlike other export methods, this method does not return data and directly triggers the download.
> After v0.6.0, an additional ExportPDF plugin needs to be registered
```js
import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF.js'
MindMap.usePlugin(ExportPDF)
```
### json(name, withConfig)
`name`It is temporarily useless, just pass an empty string

View File

@@ -4,7 +4,8 @@
<p>The <code>Export</code> plugin provides the export function.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> Export <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/Export.js&#x27;</span>
<span class="hljs-keyword">import</span> Export <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/Export.js&#x27;</span>
<span class="hljs-comment">// import Export from &#x27;simple-mind-map/src/Export.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(Export)
</code></pre>
@@ -62,6 +63,12 @@ a.click()
</blockquote>
<p><code>name</code>File name</p>
<p>Export as <code>pdf</code>. Unlike other export methods, this method does not return data and directly triggers the download.</p>
<blockquote>
<p>After v0.6.0, an additional ExportPDF plugin needs to be registered</p>
</blockquote>
<pre class="hljs"><code><span class="hljs-keyword">import</span> ExportPDF <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/ExportPDF.js&#x27;</span>
MindMap.usePlugin(ExportPDF)
</code></pre>
<h3>json(name, withConfig)</h3>
<p><code>name</code>It is temporarily useless, just pass an empty string</p>
<p><code>withConfig``Boolean</code>, default <code>true</code>, Whether the data contains configuration, otherwise it is pure mind map node data</p>

View File

@@ -12,7 +12,8 @@ Please refer to the [Instantiation Options](/mind-map/#/doc/zh/constructor) of t
```js
import MindMap from 'simple-mind-map'
import Drag from 'simple-mind-map/src/Drag.js'
import Drag from 'simple-mind-map/src/plugins/Drag.js'
// import Drag from 'simple-mind-map/src/Drag.js' Use this path for versions below v0.6.0
MindMap.usePlugin(Drag)
```

View File

@@ -7,7 +7,8 @@
<p>Please refer to the <a href="/mind-map/#/doc/zh/constructor">Instantiation Options</a> of the <code>MindMap</code> class for configuration.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> Drag <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/Drag.js&#x27;</span>
<span class="hljs-keyword">import</span> Drag <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/Drag.js&#x27;</span>
<span class="hljs-comment">// import Drag from &#x27;simple-mind-map/src/Drag.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(Drag)
</code></pre>

View File

@@ -65,6 +65,8 @@ The folder containing the packaged resources for the `web` folder.
[How to simulate the background image style of css in canvas](https://juejin.cn/post/7204854015463538744)
[My first Electron application](https://juejin.cn/post/7233012756314701884)
## Special Note
This project can be used for learning and reference. Please deeply experience whether it can meet your needs when using it for actual projects.
@@ -123,4 +125,15 @@ Open source is not easy. If this project is helpful to you, you can invite the a
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
<img src="../../../../assets/img/wechat.jpg" style="width: 300px" />
<img src="../../../../assets/img/wechat.jpg" style="width: 300px" />
<div style="display: flex;">
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/Think.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>Think</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/志斌.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>志斌</p>
</div>
</div>

View File

@@ -8,21 +8,21 @@
</blockquote>
<h2>Features</h2>
<ul>
<li><input type="checkbox" id="checkbox90" checked="true" /><label for="checkbox90">Plugin architecture. In addition to core functions, other functions are provided as plugins, which can be used as needed to reduce the overall volume</label></li>
<li><input type="checkbox" id="checkbox91" checked="true" /><label for="checkbox91">Supports six types of structures: logical structure diagrams, mind maps,</label>
<li><input type="checkbox" id="checkbox18" checked="true" /><label for="checkbox18">Plugin architecture. In addition to core functions, other functions are provided as plugins, which can be used as needed to reduce the overall volume</label></li>
<li><input type="checkbox" id="checkbox19" checked="true" /><label for="checkbox19">Supports six types of structures: logical structure diagrams, mind maps,</label>
organizational structure diagrams, directory organization diagrams, timeline, and fishbone diagrams</li>
<li><input type="checkbox" id="checkbox92" checked="true" /><label for="checkbox92">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
<li><input type="checkbox" id="checkbox93" checked="true" /><label for="checkbox93">Supports shortcuts</label></li>
<li><input type="checkbox" id="checkbox94" checked="true" /><label for="checkbox94">Node content supports images, icons, hyperlinks, notes, tags, and</label>
<li><input type="checkbox" id="checkbox20" checked="true" /><label for="checkbox20">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
<li><input type="checkbox" id="checkbox21" checked="true" /><label for="checkbox21">Supports shortcuts</label></li>
<li><input type="checkbox" id="checkbox22" checked="true" /><label for="checkbox22">Node content supports images, icons, hyperlinks, notes, tags, and</label>
summaries</li>
<li><input type="checkbox" id="checkbox95" checked="true" /><label for="checkbox95">Supports forward and backward navigation</label></li>
<li><input type="checkbox" id="checkbox96" checked="true" /><label for="checkbox96">Supports dragging and scaling</label></li>
<li><input type="checkbox" id="checkbox97" checked="true" /><label for="checkbox97">Supports right-click and Ctrl + left-click to select multiple items</label></li>
<li><input type="checkbox" id="checkbox98" checked="true" /><label for="checkbox98">Supports free dragging and dragging to adjust nodes</label></li>
<li><input type="checkbox" id="checkbox99" checked="true" /><label for="checkbox99">Supports various node shapes</label></li>
<li><input type="checkbox" id="checkbox100" checked="true" /><label for="checkbox100">Supports export to json, png, svg, pdf markdown, and import from json, xmind, markdown</label></li>
<li><input type="checkbox" id="checkbox101" checked="true" /><label for="checkbox101">Supports mini mapsupport watermark</label></li>
<li><input type="checkbox" id="checkbox102" checked="true" /><label for="checkbox102">Supports associative lines</label></li>
<li><input type="checkbox" id="checkbox23" checked="true" /><label for="checkbox23">Supports forward and backward navigation</label></li>
<li><input type="checkbox" id="checkbox24" checked="true" /><label for="checkbox24">Supports dragging and scaling</label></li>
<li><input type="checkbox" id="checkbox25" checked="true" /><label for="checkbox25">Supports right-click and Ctrl + left-click to select multiple items</label></li>
<li><input type="checkbox" id="checkbox26" checked="true" /><label for="checkbox26">Supports free dragging and dragging to adjust nodes</label></li>
<li><input type="checkbox" id="checkbox27" checked="true" /><label for="checkbox27">Supports various node shapes</label></li>
<li><input type="checkbox" id="checkbox28" checked="true" /><label for="checkbox28">Supports export to json, png, svg, pdf markdown, and import from json, xmind, markdown</label></li>
<li><input type="checkbox" id="checkbox29" checked="true" /><label for="checkbox29">Supports mini mapsupport watermark</label></li>
<li><input type="checkbox" id="checkbox30" checked="true" /><label for="checkbox30">Supports associative lines</label></li>
</ul>
<h2>Repository Catalog Introduction</h2>
<p>1.<code>simple-mind-map</code></p>
@@ -32,16 +32,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="checkbox103" checked="true" /><label for="checkbox103">Toolbar, which supports inserting and deleting nodes, and editing node</label>
<li><input type="checkbox" id="checkbox31" checked="true" /><label for="checkbox31">Toolbar, which supports inserting and deleting nodes, and editing node</label>
images, icons, hyperlinks, notes, tags, and summaries</li>
<li><input type="checkbox" id="checkbox104" checked="true" /><label for="checkbox104">Sidebar, with panels for basic style settings, node style settings,</label>
<li><input type="checkbox" id="checkbox32" checked="true" /><label for="checkbox32">Sidebar, with panels for basic style settings, node style settings,</label>
outline, theme selection, and structure selection</li>
<li><input type="checkbox" id="checkbox105" checked="true" /><label for="checkbox105">Import and export functionality; data is saved in the browser's local</label>
<li><input type="checkbox" id="checkbox33" checked="true" /><label for="checkbox33">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="checkbox106" checked="true" /><label for="checkbox106">Right-click menu, which supports operations such as expanding, collapsing,</label>
<li><input type="checkbox" id="checkbox34" checked="true" /><label for="checkbox34">Right-click menu, which supports operations such as expanding, collapsing,</label>
and organizing layout</li>
<li><input type="checkbox" id="checkbox107" checked="true" /><label for="checkbox107">Bottom bar, which supports node and word count statistics, switching</label>
<li><input type="checkbox" id="checkbox35" checked="true" /><label for="checkbox35">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>
@@ -53,6 +53,7 @@ full screen, support mini map</li>
<p><a href="https://juejin.cn/post/7157681502506090510">Only a hundred lines of code are needed to add local file operation capability to your Web page. Are you sure not to try?</a></p>
<p><a href="https://juejin.cn/post/7199666255883927612">When you press the direction key, how does the TV find the next focus</a></p>
<p><a href="https://juejin.cn/post/7204854015463538744">How to simulate the background image style of css in canvas</a></p>
<p><a href="https://juejin.cn/post/7233012756314701884">My first Electron application</a></p>
<h2>Special Note</h2>
<p>This project can be used for learning and reference. Please deeply experience whether it can meet your needs when using it for actual projects.</p>
<p>This project may not have fully tested every function point, so there may be bugs. In addition, when the number of nodes is very large, there may be some performance issues. Because everyone can accept different levels of congestion, you can test the maximum number of nodes yourself.</p>
@@ -85,6 +86,16 @@ full screen, support mini map</li>
</blockquote>
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
<img src="../../../../assets/img/wechat.jpg" style="width: 300px" />
<div style="display: flex;">
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/Think.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>Think</p>
</div>
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
<img src="../../../../assets/avatar/志斌.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
<p>志斌</p>
</div>
</div>
</div>
</template>

View File

@@ -11,7 +11,7 @@ includes some built-in shortcuts and can also be added manually. The
Add a shortcut
`key`: Shortcut key, key values can be viewed at
[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js)
[keyMap.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/command/keyMap.js)
Example:
```js

View File

@@ -8,7 +8,7 @@ includes some built-in shortcuts and can also be added manually. The
<h3>addShortcut(key, fn)</h3>
<p>Add a shortcut</p>
<p><code>key</code>: Shortcut key, key values can be viewed at
<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js</a>
<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/command/keyMap.js">keyMap.js</a>
Example:</p>
<pre class="hljs"><code><span class="hljs-comment">// Single key</span>
mindMap.keyCommand.addShortcut(<span class="hljs-string">&quot;Enter&quot;</span>, <span class="hljs-function">() =&gt;</span> {});

View File

@@ -8,7 +8,8 @@
```js
import MindMap from 'simple-mind-map'
import KeyboardNavigation from 'simple-mind-map/src/KeyboardNavigation.js'
import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
// import KeyboardNavigation from 'simple-mind-map/src/KeyboardNavigation.js' Use this path for versions below v0.6.0
MindMap.usePlugin(KeyboardNavigation)
```

View File

@@ -7,7 +7,8 @@
<p><code>KeyboardNavigation</code> plugin provides keyboard navigation function, that is, when you press the direction key, it will automatically find the next node and activate it.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> KeyboardNavigation <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/KeyboardNavigation.js&#x27;</span>
<span class="hljs-keyword">import</span> KeyboardNavigation <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/KeyboardNavigation.js&#x27;</span>
<span class="hljs-comment">// import KeyboardNavigation from &#x27;simple-mind-map/src/KeyboardNavigation.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(KeyboardNavigation)
</code></pre>

View File

@@ -12,7 +12,8 @@ viewport location, and can be quickly positioned by dragging on the small map.
```js
import MindMap from 'simple-mind-map'
import MiniMap from 'simple-mind-map/src/MiniMap.js'
import MiniMap from 'simple-mind-map/src/plugins/MiniMap.js'
// import MiniMap from 'simple-mind-map/src/MiniMap.js' Use this path for versions below v0.6.0
MindMap.usePlugin(MiniMap)
```

View File

@@ -11,7 +11,8 @@ part of the mind map content. The viewport frame can be used to view the current
viewport location, and can be quickly positioned by dragging on the small map.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> MiniMap <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/MiniMap.js&#x27;</span>
<span class="hljs-keyword">import</span> MiniMap <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/MiniMap.js&#x27;</span>
<span class="hljs-comment">// import MiniMap from &#x27;simple-mind-map/src/MiniMap.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(MiniMap)
</code></pre>

View File

@@ -56,6 +56,12 @@ Whether the node is currently being dragged
## Methods
### hasCustomStyle()
> v0.6.2+
Gets whether a custom style has been set.
### getSize()
Update the width and height of the node by recreating the node content, and return a Boolean value indicating whether the width and height have changed

View File

@@ -31,6 +31,11 @@
</blockquote>
<p>Whether the node is currently being dragged</p>
<h2>Methods</h2>
<h3>hasCustomStyle()</h3>
<blockquote>
<p>v0.6.2+</p>
</blockquote>
<p>Gets whether a custom style has been set.</p>
<h3>getSize()</h3>
<p>Update the width and height of the node by recreating the node content, and return a Boolean value indicating whether the width and height have changed</p>
<h3>render()</h3>

View File

@@ -20,7 +20,8 @@ The version of `v0.5.7+` directly uses `html2canvas` to convert the entire `svg`
```js
import MindMap from 'simple-mind-map'
import RichText from 'simple-mind-map/src/RichText.js'
import RichText from 'simple-mind-map/src/plugins/RichText.js'
// import RichText from 'simple-mind-map/src/RichText.js' Use this path for versions below v0.6.0
MindMap.usePlugin(RichText, opt?)
```

View File

@@ -17,7 +17,8 @@
<p>The version of <code>v0.5.7+</code> directly uses <code>html2canvas</code> to convert the entire <code>svg</code>, which is no longer an issue with speed. However, there is currently a bug where the color of the node does not take effect after export.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> RichText <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/RichText.js&#x27;</span>
<span class="hljs-keyword">import</span> RichText <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/RichText.js&#x27;</span>
<span class="hljs-comment">// import RichText from &#x27;simple-mind-map/src/RichText.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(RichText, opt?)
</code></pre>

View File

@@ -6,7 +6,8 @@ The `Select` plugin provides the function of right-clicking to select multiple n
```js
import MindMap from 'simple-mind-map'
import Select from 'simple-mind-map/src/Select.js'
import Select from 'simple-mind-map/src/plugins/Select.js'
// import Select from 'simple-mind-map/src/Select.js' Use this path for versions below v0.6.0
MindMap.usePlugin(Select)
```

View File

@@ -4,7 +4,8 @@
<p>The <code>Select</code> plugin provides the function of right-clicking to select multiple nodes.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> Select <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/Select.js&#x27;</span>
<span class="hljs-keyword">import</span> Select <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/Select.js&#x27;</span>
<span class="hljs-comment">// import Select from &#x27;simple-mind-map/src/Select.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(Select)
</code></pre>

View File

@@ -77,7 +77,7 @@ If you need a file in the format of `umd` module, such as `CDN` in the browser,
<script scr="simpleMindMap.umd.min.js"></script>
```
A global variable `window.simpleMindMap` will be created.
A global variable `window.simpleMindMap` will be created. you can get `MindMap` constructor by `window.simpleMindMap.default`, for more detail info you can log `window.simpleMindMap`.
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.

View File

@@ -57,7 +57,7 @@ compile this dependency:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;simpleMindMap.css&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">scr</span>=<span class="hljs-string">&quot;simpleMindMap.umd.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>A global variable <code>window.simpleMindMap</code> will be created.</p>
<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>
<h2>Development</h2>

View File

@@ -0,0 +1,18 @@
# TouchEvent plugin
> v0.6.0+
This plugin supports mobile touch events for users. The principle is to listen for 'touchstart', 'touchmove', and 'touchend' events on the mobile end, and then dispatch corresponding mouse events.
Currently, it supports single finger touch to move the canvas, click to activate nodes, double finger zoom the canvas, single finger double-click to reset and edit nodes.
## Register
```js
import MindMap from 'simple-mind-map'
import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
MindMap.usePlugin(TouchEvent)
```
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.touchEvent`.

View File

@@ -0,0 +1,28 @@
<template>
<div>
<h1>TouchEvent plugin</h1>
<blockquote>
<p>v0.6.0+</p>
</blockquote>
<p>This plugin supports mobile touch events for users. The principle is to listen for 'touchstart', 'touchmove', and 'touchend' events on the mobile end, and then dispatch corresponding mouse events.</p>
<p>Currently, it supports single finger touch to move the canvas, click to activate nodes, double finger zoom the canvas, single finger double-click to reset and edit nodes.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> TouchEvent <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/TouchEvent.js&#x27;</span>
MindMap.usePlugin(TouchEvent)
</code></pre>
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.touchEvent</code>.</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -5,6 +5,12 @@ through `mindMap.view`
## Methods
### fit()
> v0.6.0+
Zoom the mind map to fit the canvas.
### translateX(step)
Translate in the `x` direction, `step`: number of pixels to translate
@@ -29,11 +35,19 @@ Translate the `y` direction to a specific position
Revert to the default transformation
### narrow()
### narrow(cx, cy)
- `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
Zoom out
### enlarge()
### enlarge(cx, cy)
- `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
Zoom in
@@ -50,8 +64,12 @@ Get the current transform data, can be used for display
Dynamically set transform data, transform data can be obtained through the
getTransformData method"
### setScale(scale)
### setScale(scale, cx, cy)
> v0.2.17+
- `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
Setting Zoom

View File

@@ -4,6 +4,11 @@
<p>The <code>view</code> instance is responsible for view operations, and can be obtained
through <code>mindMap.view</code></p>
<h2>Methods</h2>
<h3>fit()</h3>
<blockquote>
<p>v0.6.0+</p>
</blockquote>
<p>Zoom the mind map to fit the canvas.</p>
<h3>translateX(step)</h3>
<p>Translate in the <code>x</code> direction, <code>step</code>: number of pixels to translate</p>
<h3>translateY(step)</h3>
@@ -20,9 +25,25 @@ through <code>mindMap.view</code></p>
<p>Translate the <code>y</code> direction to a specific position</p>
<h3>reset()</h3>
<p>Revert to the default transformation</p>
<h3>narrow()</h3>
<h3>narrow(cx, cy)</h3>
<ul>
<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>
<p><code>cy</code>:v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas</p>
</li>
</ul>
<p>Zoom out</p>
<h3>enlarge()</h3>
<h3>enlarge(cx, cy)</h3>
<ul>
<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>
<p><code>cy</code>:v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas</p>
</li>
</ul>
<p>Zoom in</p>
<h3>getTransformData()</h3>
<blockquote>
@@ -35,10 +56,18 @@ through <code>mindMap.view</code></p>
</blockquote>
<p>Dynamically set transform data, transform data can be obtained through the
getTransformData method&quot;</p>
<h3>setScale(scale)</h3>
<h3>setScale(scale, cx, cy)</h3>
<blockquote>
<p>v0.2.17+</p>
</blockquote>
<ul>
<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>
<p><code>cy</code>:v0.6.4+Zoom to the specified position on the canvas, default to the center point of the canvas</p>
</li>
</ul>
<p>Setting Zoom</p>
</div>

View File

@@ -10,7 +10,8 @@ Please refer to the [Instantiation Options](/mind-map/#/doc/zh/constructor) of t
```js
import MindMap from 'simple-mind-map'
import Watermark from 'simple-mind-map/src/Watermark.js'
import Watermark from 'simple-mind-map/src/plugins/Watermark.js'
// import Watermark from 'simple-mind-map/src/Watermark.js' Use this path for versions below v0.6.0
MindMap.usePlugin(Watermark)
```

View File

@@ -8,7 +8,8 @@
<p>Please refer to the <a href="/mind-map/#/doc/zh/constructor">Instantiation Options</a> of the <code>MindMap</code> class for configuration.</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">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> Watermark <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/Watermark.js&#x27;</span>
<span class="hljs-keyword">import</span> Watermark <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/Watermark.js&#x27;</span>
<span class="hljs-comment">// import Watermark from &#x27;simple-mind-map/src/Watermark.js&#x27; Use this path for versions below v0.6.0</span>
MindMap.usePlugin(Watermark)
</code></pre>

View File

@@ -26,6 +26,7 @@ export default [
{ path: 'course17', title: '导入和导出' },
{ path: 'course18', title: '如何持久化数据' },
{ path: 'course19', title: '插入和扩展节点图标' },
{ path: 'course20', title: '如何自定义节点内容' },
{ path: 'doExport', title: 'Export 插件' },
{ path: 'drag', title: 'Drag插件' },
{ path: 'introduction', title: '简介' },
@@ -44,7 +45,8 @@ export default [
{ path: 'watermark', title: 'Watermark插件' },
{ path: 'xmind', title: 'XMind解析' },
{ path: 'deploy', title: '部署' },
{ path: 'client', title: '客户端' }
{ path: 'client', title: '客户端' },
{ path: 'touchEvent', title: 'TouchEvent插件' }
]
},
{
@@ -72,7 +74,8 @@ export default [
{ path: 'view', title: 'View instance' },
{ path: 'watermark', title: 'Watermark plugin' },
{ path: 'xmind', title: 'XMind parse' },
{ path: 'deploy', title: 'Deploy' }
{ path: 'deploy', title: 'Deploy' },
{ path: 'touchEvent', title: 'TouchEvent plugin' }
]
}
]

View File

@@ -12,7 +12,8 @@
```js
import MindMap from 'simple-mind-map'
import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
// import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js' v0.6.0以下版本使用该路径
MindMap.usePlugin(AssociativeLine)
```

View File

@@ -13,7 +13,8 @@
<p>该插件用于支持添加关联线</p>
<h2>注册</h2>
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map&#x27;</span>
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/AssociativeLine.js&#x27;</span>
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/plugins/AssociativeLine.js&#x27;</span>
<span class="hljs-comment">// import AssociativeLine from &#x27;simple-mind-map/src/AssociativeLine.js&#x27; v0.6.0以下版本使用该路径</span>
MindMap.usePlugin(AssociativeLine)
</code></pre>

View File

@@ -1,5 +1,41 @@
# Changelog
## 0.6.4-fix.1
新增1.鼠标滚轮缩放时默认以鼠标当前位置为中心进行缩放,可以通过配置关闭该特性。
修复1.修复改变了画布大小后缩放中心点默认值不随之更新的问题。
## 0.6.4
新增1.默认以画布中心点进行缩放。 2.优化移动端双指缩放,以双指中心位置为中心点进行缩放。
## 0.6.3
修复1.修复概要节点会响应插入节点快捷键的问题。
新增1.支持自定义节点内容。
## 0.6.2
修复1.修复富文本模式下,新建节点不随主题变化而变化的问题。
## 0.6.1
修复1.修复将鼠标滚动改为移动画布行为后,使用触控板操作时移动灵敏度过高的问题。
## 0.6.0-fix.1
修复1.修复没有设置过背景样式的情况下销毁思维导图报错的问题。
## 0.6.0
破坏性更新调整了simple-mind-map源码的目录结构主要影响1.插件的引入路径需要修改。2.constant文件路径需要修改。
新增1.支持一键缩放至适应画布功能。 2.按住Ctrl键多选功能可通过配置按需开启。 3.支持设置为左键多选节点,右键拖动画布。 4.支持控制节点是否允许编辑。 5.新增销毁思维导图的方法。 6.新增触摸事件支持插件。
修复1.修复按住ctrl键多选节点时不会触发节点的click事件的问题。 2.修复清空一个节点后再输入文字时节点样式丢失的问题。
## 0.5.11
新增:支持关联性文本编辑。

View File

@@ -1,6 +1,24 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.6.4-fix.1</h2>
<p>新增1.鼠标滚轮缩放时默认以鼠标当前位置为中心进行缩放可以通过配置关闭该特性</p>
<p>修复1.修复改变了画布大小后缩放中心点默认值不随之更新的问题</p>
<h2>0.6.4</h2>
<p>新增1.默认以画布中心点进行缩放 2.优化移动端双指缩放以双指中心位置为中心点进行缩放</p>
<h2>0.6.3</h2>
<p>修复1.修复概要节点会响应插入节点快捷键的问题</p>
<p>新增1.支持自定义节点内容</p>
<h2>0.6.2</h2>
<p>修复1.修复富文本模式下新建节点不随主题变化而变化的问题</p>
<h2>0.6.1</h2>
<p>修复1.修复将鼠标滚动改为移动画布行为后使用触控板操作时移动灵敏度过高的问题</p>
<h2>0.6.0-fix.1</h2>
<p>修复1.修复没有设置过背景样式的情况下销毁思维导图报错的问题</p>
<h2>0.6.0</h2>
<p>破坏性更新调整了simple-mind-map源码的目录结构主要影响1.插件的引入路径需要修改2.constant文件路径需要修改</p>
<p>新增1.支持一键缩放至适应画布功能 2.按住Ctrl键多选功能可通过配置按需开启 3.支持设置为左键多选节点右键拖动画布 4.支持控制节点是否允许编辑 5.新增销毁思维导图的方法 6.新增触摸事件支持插件</p>
<p>修复1.修复按住ctrl键多选节点时不会触发节点的click事件的问题 2.修复清空一个节点后再输入文字时节点样式丢失的问题</p>
<h2>0.5.11</h2>
<p>新增支持关联性文本编辑</p>
<p>优化优化主题配置更新改变不涉及节点大小的配置不触发节点重新计算</p>

View File

@@ -25,11 +25,11 @@ const mindMap = new MindMap({
| 字段名称 | 类型 | 默认值 | 描述 | 是否必填 |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ | -------- |
| el | Element | | 容器元素必须为DOM元素 | 是 |
| data | Object | {} | 思维导图数据,可参考:[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) | |
| data | Object | {} | 思维导图数据,可参考:[exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) | |
| layout | String | logicalStructure | 布局类型可选列表logicalStructure逻辑结构图、mindMap思维导图、catalogOrganization目录组织图、organizationStructure组织结构图、timelinev0.5.4+时间轴、timeline2v0.5.4+上下交替型时间轴、fishbonev0.5.4+,鱼骨图) | |
| fishboneDegv0.5.4+ | Number | 45 | 设置鱼骨结构图的斜线角度 | |
| theme | String | default | 主题可选列表default默认、classic脑图经典、minions小黄人、pinkGrape粉红葡萄、mint薄荷、gold金色vip、vitalityOrange活力橙、greenLeaf绿叶、dark2暗色2、skyGreen天清绿、classic2脑图经典2、classic3脑图经典3、classic4脑图经典4v0.2.0+、classicGreen经典绿、classicBlue经典蓝、blueSky天空蓝、brainImpairedPink脑残粉、dark暗色、earthYellow泥土黄、freshGreen清新绿、freshRed清新红、romanticPurple浪漫紫、simpleBlackv0.5.4+简约黑、courseGreenv0.5.4+课程绿、coffeev0.5.4+咖啡、redSpiritv0.5.4+红色精神、blackHumourv0.5.4+黑色幽默、lateNightOfficev0.5.4+深夜办公室、blackGoldv0.5.4+黑金、avocadov.5.10-fix.2+牛油果、autumnv.5.10-fix.2+秋天、orangeJuicev.5.10-fix.2+橙汁) | |
| themeConfig | Object | {} | 主题配置,会和所选择的主题进行合并,可用字段可参考:[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
| themeConfig | Object | {} | 主题配置,会和所选择的主题进行合并,可用字段可参考:[default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
| scaleRatio | Number | 0.1 | 放大缩小的增量比例 | |
| maxTag | Number | 5 | 节点里最多显示的标签数量,多余的会被丢弃 | |
| exportPadding | Number | 20 | 导出图片时的内边距 | |
@@ -62,6 +62,14 @@ const mindMap = new MindMap({
| alwaysShowExpandBtnv0.5.8+ | Boolean | false | 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示 | |
| iconListv0.5.8+ | Array | [] | 扩展节点可插入的图标,数组的每一项为一个对象,对象详细结构请参考下方【图标配置】表格 | |
| maxNodeCacheCountv0.5.10+ | Number | 1000 | 节点最大缓存数量。为了优化性能,内部会维护一个节点缓存池,用来复用节点,通过该属性可以指定池的最大缓存数量 | |
| defaultAssociativeLineTextv0.5.11+ | String | 关联 | 关联线默认文字 | |
| fitPaddingv0.6.0+ | Number | 50 | 思维导图适应画布大小时的内边距单位px | |
| enableCtrlKeyNodeSelectionv0.6.0+ | Boolean | true | 是否开启按住ctrl键多选节点的功能 | |
| useLeftKeySelectionRightKeyDragv0.6.0+ | Boolean | false | 设置为左键多选节点,右键拖动画布 | |
| beforeTextEditv0.6.0+ | Function/null | null | 节点即将进入编辑前的回调方法如果该方法返回true以外的值那么将取消编辑函数可以返回一个值或一个Promise回调参数为节点实例 | |
| isUseCustomNodeContentv0.6.3+ | Boolean | false | 是否自定义节点内容 | |
| customCreateNodeContentv0.6.3+ | Function/null | null | 如果`isUseCustomNodeContent`设为`true`,那么需要使用该选项传入一个方法,接收节点实例`node`为参数(如果要获取该节点的数据,可以通过`node.nodeData.data`需要返回自定义节点内容元素也就是DOM节点如果某个节点不需要自定义那么返回`null`即可 | |
| mouseScaleCenterUseMousePositionv0.6.4-fix.1+ | Boolean | true | 鼠标缩放是否以鼠标当前位置为中心点,否则以画布中心点 | |
### 水印配置
@@ -138,6 +146,12 @@ mindMap.setTheme('主题名称')
## 实例方法
### destroy()
> v0.6.0+
销毁思维导图。会移除注册的插件、移除监听的事件、删除画布的所有节点。
### getSvgData({ paddingX = 0, paddingY = 0 })
> v0.3.0+
@@ -199,7 +213,7 @@ mindMap.setTheme('主题名称')
| mousemove | el元素的鼠标移动事件 | e事件对象、thisEvent事件类实例 |
| drag | 如果是按住左键拖动的话会触发拖动事件 | e事件对象、thisEvent事件类实例 |
| mouseup | el元素的鼠标松开事件 | e事件对象、thisEvent事件类实例 |
| mousewheel | 鼠标滚动事件 | e事件对象、dir向上up还是向下down滚动、thisEvent事件类实例 |
| mousewheel | 鼠标滚动事件 | e事件对象、dir向上up还是向下down滚动、thisEvent事件类实例、isTouchPadv0.6.1+,是否是触控板触发的事件) |
| contextmenu | svg画布的鼠标右键菜单事件 | e事件对象 |
| node_click | 节点的单击事件 | this节点实例、e事件对象 |
| node_mousedown | 节点的鼠标按下事件 | this节点实例、e事件对象 |
@@ -293,8 +307,8 @@ mindMap.updateConfig({
| SELECT_ALL | 全选 | |
| BACK | 回退指定的步数 | step要回退的步数默认为1 |
| FORWARD | 前进指定的步数 | step要前进的步数默认为1 |
| INSERT_NODE | 插入同级节点,操作节点为当前激活的节点或指定节点,如果有多个激活节点,只会对第一个有效 | openEditv0.4.6+,是否激活新插入的节点并进入编辑模式,默认为`true`)、 appointNodesv0.4.7+,可选,指定节点,指定多个节点可以传一个数组)、 appointData可选指定新创建节点的数据比如{text: 'xxx', ...},详细结构可以参考[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_CHILD_NODE | 插入子节点,操作节点为当前激活的节点或指定节点 | openEditv0.4.6+,是否激活新插入的节点并进入编辑模式,默认为`true`)、 appointNodesv0.4.7+,可选,指定节点,指定多个节点可以传一个数组)、 appointData可选指定新创建节点的数据比如{text: 'xxx', ...},详细结构可以参考[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_NODE | 插入同级节点,操作节点为当前激活的节点或指定节点,如果有多个激活节点,只会对第一个有效 | openEditv0.4.6+,是否激活新插入的节点并进入编辑模式,默认为`true`)、 appointNodesv0.4.7+,可选,指定节点,指定多个节点可以传一个数组)、 appointData可选指定新创建节点的数据比如{text: 'xxx', ...},详细结构可以参考[exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| INSERT_CHILD_NODE | 插入子节点,操作节点为当前激活的节点或指定节点 | openEditv0.4.6+,是否激活新插入的节点并进入编辑模式,默认为`true`)、 appointNodesv0.4.7+,可选,指定节点,指定多个节点可以传一个数组)、 appointData可选指定新创建节点的数据比如{text: 'xxx', ...},详细结构可以参考[exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) |
| UP_NODE | 上移节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的第一个节点使用无效 | |
| DOWN_NODE | 操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的最后一个节点使用无效 | |
| REMOVE_NODE | 删除节点,操作节点为当前激活的节点或指定节点 | appointNodesv0.4.7+,可选,指定节点,指定多个节点可以传一个数组) |
@@ -310,10 +324,10 @@ mindMap.updateConfig({
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据 | node要设置的节点、data对象要更新的数据`{expand: true}` |
| SET_NODE_TEXT | 设置节点文本 | node要设置的节点、text要设置的文本字符串换行可以使用`\n`、richTextv0.4.0+,如果要设置的是富文本字符,需要设为`true` |
| SET_NODE_IMAGE | 设置节点图片 | node要设置的节点、imgData对象图片信息结构为`{url, title, width, height}`,图片的宽高必须要传) |
| SET_NODE_ICON | 设置节点图标 | node要设置的节点、icons数组预定义的图片名称组成的数组可用图标可在[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件里的`nodeIconList`列表里获取到,图标名称为`type_name`,如`['priority_1']` |
| SET_NODE_ICON | 设置节点图标 | node要设置的节点、icons数组预定义的图片名称组成的数组可用图标可在[icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件里的`nodeIconList`列表里获取到,图标名称为`type_name`,如`['priority_1']` |
| SET_NODE_HYPERLINK | 设置节点超链接 | node要设置的节点、link超链接地址、title超链接名称可选 |
| SET_NODE_NOTE | 设置节点备注 | node要设置的节点、note备注文字 |
| SET_NODE_TAG | 设置节点标签 | node要设置的节点、tag字符串数组内置颜色信息可在[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js)里获取到) |
| SET_NODE_TAG | 设置节点标签 | node要设置的节点、tag字符串数组内置颜色信息可在[constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/constants/constant.js)里获取到) |
| INSERT_AFTERv0.1.5+ | 将节点移动到另一个节点的后面 | node要移动的节点、 exist目标节点 |
| INSERT_BEFOREv0.1.5+ | 将节点移动到另一个节点的前面 | node要移动的节点、 exist目标节点 |
| MOVE_NODE_TOv0.1.5+ | 移动一个节点作为另一个节点的子节点 | node要移动的节点、 toNode目标节点 |
@@ -321,7 +335,7 @@ mindMap.updateConfig({
| REMOVE_GENERALIZATIONv0.2.0+ | 删除节点概要 | |
| SET_NODE_CUSTOM_POSITIONv0.2.0+ | 设置节点自定义位置 | node要设置的节点、 left自定义的x坐标默认为undefined、 top自定义的y坐标默认为undefined |
| RESET_LAYOUTv0.2.0+ | 一键整理布局 | |
| SET_NODE_SHAPEv0.2.4+ | 设置节点形状 | node要设置的节点、shape形状全部形状https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js |
| SET_NODE_SHAPEv0.2.4+ | 设置节点形状 | node要设置的节点、shape形状全部形状[Shape.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/render/node/Shape.js) |
### setData(data)

View File

@@ -39,7 +39,7 @@
<td>data</td>
<td>Object</td>
<td>{}</td>
<td>思维导图数据可参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a></td>
<td>思维导图数据可参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a></td>
<td></td>
</tr>
<tr>
@@ -67,7 +67,7 @@
<td>themeConfig</td>
<td>Object</td>
<td>{}</td>
<td>主题配置会和所选择的主题进行合并可用字段可参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js</a></td>
<td>主题配置会和所选择的主题进行合并可用字段可参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">default.js</a></td>
<td></td>
</tr>
<tr>
@@ -294,6 +294,62 @@
<td>节点最大缓存数量为了优化性能内部会维护一个节点缓存池用来复用节点通过该属性可以指定池的最大缓存数量</td>
<td></td>
</tr>
<tr>
<td>defaultAssociativeLineTextv0.5.11+</td>
<td>String</td>
<td>关联</td>
<td>关联线默认文字</td>
<td></td>
</tr>
<tr>
<td>fitPaddingv0.6.0+</td>
<td>Number</td>
<td>50</td>
<td>思维导图适应画布大小时的内边距单位px</td>
<td></td>
</tr>
<tr>
<td>enableCtrlKeyNodeSelectionv0.6.0+</td>
<td>Boolean</td>
<td>true</td>
<td>是否开启按住ctrl键多选节点的功能</td>
<td></td>
</tr>
<tr>
<td>useLeftKeySelectionRightKeyDragv0.6.0+</td>
<td>Boolean</td>
<td>false</td>
<td>设置为左键多选节点右键拖动画布</td>
<td></td>
</tr>
<tr>
<td>beforeTextEditv0.6.0+</td>
<td>Function/null</td>
<td>null</td>
<td>节点即将进入编辑前的回调方法如果该方法返回true以外的值那么将取消编辑函数可以返回一个值或一个Promise回调参数为节点实例</td>
<td></td>
</tr>
<tr>
<td>isUseCustomNodeContentv0.6.3+</td>
<td>Boolean</td>
<td>false</td>
<td>是否自定义节点内容</td>
<td></td>
</tr>
<tr>
<td>customCreateNodeContentv0.6.3+</td>
<td>Function/null</td>
<td>null</td>
<td>如果<code>isUseCustomNodeContent</code>设为<code>true</code>那么需要使用该选项传入一个方法接收节点实例<code>node</code>为参数如果要获取该节点的数据可以通过<code>node.nodeData.data</code>需要返回自定义节点内容元素也就是DOM节点如果某个节点不需要自定义那么返回<code>null</code>即可</td>
<td></td>
</tr>
<tr>
<td>mouseScaleCenterUseMousePositionv0.6.4-fix.1+</td>
<td>Boolean</td>
<td>true</td>
<td>鼠标缩放是否以鼠标当前位置为中心点否则以画布中心点</td>
<td></td>
</tr>
</tbody>
</table>
<h3>水印配置</h3>
@@ -413,6 +469,11 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
</blockquote>
<p>当前注册的所有插件列表</p>
<h2>实例方法</h2>
<h3>destroy()</h3>
<blockquote>
<p>v0.6.0+</p>
</blockquote>
<p>销毁思维导图会移除注册的插件移除监听的事件删除画布的所有节点</p>
<h3>getSvgData({ paddingX = 0, paddingY = 0 })</h3>
<blockquote>
<p>v0.3.0+</p>
@@ -507,7 +568,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>mousewheel</td>
<td>鼠标滚动事件</td>
<td>e事件对象dir向上up还是向下down滚动thisEvent事件类实例</td>
<td>e事件对象dir向上up还是向下down滚动thisEvent事件类实例isTouchPadv0.6.1+是否是触控板触发的事件</td>
</tr>
<tr>
<td>contextmenu</td>
@@ -690,12 +751,12 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>INSERT_NODE</td>
<td>插入同级节点操作节点为当前激活的节点或指定节点如果有多个激活节点只会对第一个有效</td>
<td>openEditv0.4.6+是否激活新插入的节点并进入编辑模式默认为<code>true</code> appointNodesv0.4.7+可选指定节点指定多个节点可以传一个数组 appointData可选指定新创建节点的数据比如{text: 'xxx', ...}详细结构可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a></td>
<td>openEditv0.4.6+是否激活新插入的节点并进入编辑模式默认为<code>true</code> appointNodesv0.4.7+可选指定节点指定多个节点可以传一个数组 appointData可选指定新创建节点的数据比如{text: 'xxx', ...}详细结构可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a></td>
</tr>
<tr>
<td>INSERT_CHILD_NODE</td>
<td>插入子节点操作节点为当前激活的节点或指定节点</td>
<td>openEditv0.4.6+是否激活新插入的节点并进入编辑模式默认为<code>true</code> appointNodesv0.4.7+可选指定节点指定多个节点可以传一个数组 appointData可选指定新创建节点的数据比如{text: 'xxx', ...}详细结构可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a></td>
<td>openEditv0.4.6+是否激活新插入的节点并进入编辑模式默认为<code>true</code> appointNodesv0.4.7+可选指定节点指定多个节点可以传一个数组 appointData可选指定新创建节点的数据比如{text: 'xxx', ...}详细结构可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">exampleData.js</a></td>
</tr>
<tr>
<td>UP_NODE</td>
@@ -775,7 +836,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>SET_NODE_ICON</td>
<td>设置节点图标</td>
<td>node要设置的节点icons数组预定义的图片名称组成的数组可用图标可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js</a>文件里的<code>nodeIconList</code>列表里获取到,图标名称为<code>type_name</code>,如<code>['priority_1']</code></td>
<td>node要设置的节点icons数组预定义的图片名称组成的数组可用图标可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">icons.js</a>文件里的<code>nodeIconList</code>列表里获取到图标名称为<code>type_name</code><code>['priority_1']</code></td>
</tr>
<tr>
<td>SET_NODE_HYPERLINK</td>
@@ -790,7 +851,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>SET_NODE_TAG</td>
<td>设置节点标签</td>
<td>node要设置的节点tag字符串数组内置颜色信息可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js</a>里获取到)</td>
<td>node要设置的节点tag字符串数组内置颜色信息可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/constants/constant.js">constant.js</a>里获取到</td>
</tr>
<tr>
<td>INSERT_AFTERv0.1.5+</td>
@@ -830,7 +891,7 @@ mindMap.setTheme(<span class="hljs-string">&#x27;主题名称&#x27;</span>)
<tr>
<td>SET_NODE_SHAPEv0.2.4+</td>
<td>设置节点形状</td>
<td>node要设置的节点shape形状全部形状https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js</td>
<td>node要设置的节点shape形状全部形状<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/core/render/node/Shape.js">Shape.js</a></td>
</tr>
</tbody>
</table>

View File

@@ -5,7 +5,8 @@
`simple-mind-map`内置了很多主题,可以通过如下方式获取到所有的内置主题列表:
```js
import { themeList } from 'simple-mind-map/src/utils/constant'
import { themeList } from 'simple-mind-map/src/constants/constant'
// import { themeList } from 'simple-mind-map/src/utils/constant' v0.6.0以下版本使用该路径
```
可以在实例化`simple-mind-map`时指定使用的主题:

View File

@@ -3,7 +3,8 @@
<h1>主题</h1>
<h2>使用和切换主题</h2>
<p><code>simple-mind-map</code>内置了很多主题可以通过如下方式获取到所有的内置主题列表</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> { themeList } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/utils/constant&#x27;</span>
<pre class="hljs"><code><span class="hljs-keyword">import</span> { themeList } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/constants/constant&#x27;</span>
<span class="hljs-comment">// import { themeList } from &#x27;simple-mind-map/src/utils/constant&#x27; v0.6.0以下版本使用该路径</span>
</code></pre>
<p>可以在实例化<code>simple-mind-map</code>时指定使用的主题</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({

View File

@@ -60,6 +60,8 @@ mindMap.export('png', true, '文件名')
mindMap.export('pdf', true, '文件名')
```
> 从v0.6.0+要导出pdf需要额外注册一个ExportPDF插件。
### 导出为svg
导出为`svg`可以传递的参数如下:

View File

@@ -38,6 +38,9 @@ mindMap.export(<span class="hljs-string">&#x27;json&#x27;</span>, <span class="h
<pre class="hljs"><code>mindMap.export(<span class="hljs-string">&#x27;png&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>)
mindMap.export(<span class="hljs-string">&#x27;pdf&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>)
</code></pre>
<blockquote>
<p>从v0.6.0+要导出pdf需要额外注册一个ExportPDF插件</p>
</blockquote>
<h3>导出为svg</h3>
<p>导出为<code>svg</code>可以传递的参数如下</p>
<pre class="hljs"><code>mindMap.export(type, isDownload, fileName, plusCssText = <span class="hljs-string">&#x27;&#x27;</span>)

View File

@@ -0,0 +1,119 @@
# 如何自定义节点内容
> 该特性v0.6.3+版本支持
如果你想自定义节点的内容,那么可以在实例化`simple-mind-map`时传入以下选项:
```js
new MindMap({
isUseCustomNodeContent: true,
customCreateNodeContent: (node) => {
// return你的自定义DOM节点
}
})
```
`customCreateNodeContent`方法会接收当前遍历到的节点实例作为参数,一般而言你会需要该节点的数据,这可以通过如下方式获取:
```js
node.nodeData.data
```
其他节点实例属性你可以自行打印出来看看。
`customCreateNodeContent`方法需要返回`DOM`节点,如果某个节点你不想自定义,那么可以返回`null`,那么还是会走内置的节点渲染逻辑。
返回的`DOM`节点的宽高需要是确定的,如果是动态的那么会导致宽高获取错误,最终导致节点定位错误和发生重叠等问题。
如果使用了自定义节点内容,那么内置的插入节点内容的相关方法你都不应该再使用,因为相当于整个节点内容都由你自己控制,另外,节点样式设置也不会再生效,切换主题也只会切换非节点内容的样式,最后,双击节点也不会再进入编辑,所以这个功能一般用于展示性的需求。
## 示例1渲染自定义DOM节点
```js
{
customCreateNodeContent: (node) => {
let div = document.createElement('div')
div.className = 'xxx'
div.style.cssText = `xxx`
div.innerHTML = `
<h1>我是自定义节点</h1>
${ node.nodeData.text }
`
return div
}
}
```
## 示例2渲染Vue2组件
如果想要使用一个相对简单的`Vue`组件,那么可以通过如下方式:
```js
import CustomNodeContent from 'CustomNodeContent.vue'
import Vue from 'vue'
{
customCreateNodeContent: (node) => {
let el = document.createElement('div')
let Comp = Vue.extend(CustomNodeContent)
let comp = new Comp({
// props
propsData: {
html: node.nodeData.data.text
}
})
comp.$mount(el)
return comp.$el
}
}
```
如果你的`Vue`组件比较复杂,里面用到了`vueRouter``vuex``i18n`等,那么要和你项目的入口组件一样,在实例化时要把这些内容也加载到组件内,不然会报错。
```js
import CustomNodeContent from 'CustomNodeContent.vue'
import Vue from 'vue'
import router from './router'
import store from './store'
import i18n from './i18n'
{
customCreateNodeContent: (node) => {
let el = document.createElement('div')
let Comp = Vue.extend(CustomNodeContent)
let comp = new Comp({
// props
propsData: {
html: node.nodeData.data.text
},
router,
store,
i18n
})
comp.$mount(el)
return comp.$el
}
}
```
## 示例3渲染Vue3组件
```js
import { createApp } from "vue"
import CustomNodeContent from './CustomNodeContent.vue'
{
customCreateNodeContent: (node) => {
let el = document.createElement('div')
const app = createApp(CustomNodeContent, {// props
html: node.nodeData.data.text
})
app.mount(el)
return el
}
}
```
## 示例4渲染react组件
如果你成功渲染了`react`组件,欢迎[提交](https://github.com/wanglin2/mind-map/issues/new)示例代码给我~

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