Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dcfdcc44a | ||
|
|
67422df3ff | ||
|
|
2ad7536eb7 | ||
|
|
6f56e5c4e6 | ||
|
|
5ae8ebe590 | ||
|
|
6ecb97e4e5 | ||
|
|
c8f938dd3e | ||
|
|
0d29e29162 | ||
|
|
be1b3dffce | ||
|
|
3ba2dbe415 | ||
|
|
19a96c92a9 | ||
|
|
c265e3e437 | ||
|
|
7434ac2648 | ||
|
|
63d73a73aa | ||
|
|
00f9258a4d | ||
|
|
7087b43d39 | ||
|
|
945a78b7b1 | ||
|
|
55acc19ab8 | ||
|
|
410f0be05e | ||
|
|
2d7c091071 | ||
|
|
9bf58a54ce | ||
|
|
231adeea44 | ||
|
|
0ea618af39 | ||
|
|
f66297ff99 | ||
|
|
3113bf2e1f | ||
|
|
8c114dac02 | ||
|
|
06dba79272 | ||
|
|
8441986ca7 | ||
|
|
c8b50908e1 | ||
|
|
7e11fde892 | ||
|
|
3d9f3bd7a8 | ||
|
|
46e11649b0 | ||
|
|
161ef7590c | ||
|
|
ca660a3c74 | ||
|
|
7a24872331 | ||
|
|
eb4ea9fb3a | ||
|
|
64228c02ff | ||
|
|
f184a5d948 |
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
dist_electron
|
||||
@@ -26,6 +26,7 @@ Demo:[https://wanglin2.github.io/mind-map/](https://wanglin2.github.io/mind-ma
|
||||
- [x] 支持多种节点形状
|
||||
- [x] 支持导出为`json`、`png`、`svg`、`pdf`,支持从`json`、`xmind`导入
|
||||
- [x] 支持小地图
|
||||
- [x] 支持关联线
|
||||
|
||||
# 安装
|
||||
|
||||
@@ -55,4 +56,8 @@ const mindMap = new MindMap({
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
MIT
|
||||
|
||||
# 微信交流群
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 254 KiB |
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="./dist/logo.png"><title>一个简单的web思维导图实现</title><link href="dist/js/chunk-2d0a3179.f79d6590.js" rel="prefetch"><link href="dist/js/chunk-2d0aa579.d901cc5e.js" rel="prefetch"><link href="dist/js/chunk-2d0aa978.ae72a285.js" rel="prefetch"><link href="dist/js/chunk-2d0ab10b.0a72e8ef.js" rel="prefetch"><link href="dist/js/chunk-2d0abe0f.f7178a38.js" rel="prefetch"><link href="dist/js/chunk-2d0b361e.abfe0d6c.js" rel="prefetch"><link href="dist/js/chunk-2d0b91e5.de98db92.js" rel="prefetch"><link href="dist/js/chunk-2d0b92c3.a48a667e.js" rel="prefetch"><link href="dist/js/chunk-2d0bd54e.e56450f0.js" rel="prefetch"><link href="dist/js/chunk-2d0be174.1531a230.js" rel="prefetch"><link href="dist/js/chunk-2d0c0a44.d2768274.js" rel="prefetch"><link href="dist/js/chunk-2d0c14fc.a89a80b4.js" rel="prefetch"><link href="dist/js/chunk-2d0c18d8.4dad4846.js" rel="prefetch"><link href="dist/js/chunk-2d0c191e.93eb5568.js" rel="prefetch"><link href="dist/js/chunk-2d0c1a01.49c23f9e.js" rel="prefetch"><link href="dist/js/chunk-2d0d9fbc.e5848281.js" rel="prefetch"><link href="dist/js/chunk-2d0da701.2e0766e2.js" rel="prefetch"><link href="dist/js/chunk-2d0dad5f.9e9d10ae.js" rel="prefetch"><link href="dist/js/chunk-2d0db0f2.19efc7d4.js" rel="prefetch"><link href="dist/js/chunk-2d0dddce.6a579f6f.js" rel="prefetch"><link href="dist/js/chunk-2d0ddf37.d162efb9.js" rel="prefetch"><link href="dist/js/chunk-2d0de01b.f98f06e7.js" rel="prefetch"><link href="dist/js/chunk-2d0e2326.f3a9c7fc.js" rel="prefetch"><link href="dist/js/chunk-2d0e268c.2255a1cb.js" rel="prefetch"><link href="dist/js/chunk-2d0e5089.2b202405.js" rel="prefetch"><link href="dist/js/chunk-2d0e9742.a2d22497.js" rel="prefetch"><link href="dist/js/chunk-2d0f026c.9cd8732d.js" rel="prefetch"><link href="dist/js/chunk-2d2082b9.fe227afb.js" rel="prefetch"><link href="dist/js/chunk-2d208ffa.48cb1221.js" rel="prefetch"><link href="dist/js/chunk-2d20ec02.917aff76.js" rel="prefetch"><link href="dist/js/chunk-2d20f68f.acd7e356.js" rel="prefetch"><link href="dist/js/chunk-2d210a7a.5a4025ce.js" rel="prefetch"><link href="dist/js/chunk-2d216004.905379d5.js" rel="prefetch"><link href="dist/js/chunk-2d216b67.2d06497a.js" rel="prefetch"><link href="dist/js/chunk-2d217907.cc6917a4.js" rel="prefetch"><link href="dist/js/chunk-2d226d0a.3703455b.js" rel="prefetch"><link href="dist/js/chunk-2d2299c3.ffd15e65.js" rel="prefetch"><link href="dist/js/chunk-2d22bd06.cace3b1b.js" rel="prefetch"><link href="dist/js/chunk-2d2308b0.fb49d06b.js" rel="prefetch"><link href="dist/js/chunk-2d238428.266d8f0c.js" rel="prefetch"><link href="dist/js/chunk-3a2f3e67.13278516.js" rel="prefetch"><link href="dist/css/app.8a532989.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.1790fe42.css" rel="preload" as="style"><link href="dist/js/app.0642ce46.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.7f3b8358.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.1790fe42.css" rel="stylesheet"><link href="dist/css/app.8a532989.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="dist/js/chunk-vendors.7f3b8358.js"></script><script src="dist/js/app.0642ce46.js"></script></body></html>
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="./dist/logo.png"><title>一个简单的web思维导图实现</title><link href="dist/js/chunk-2d0a3179.3b27bed0.js" rel="prefetch"><link href="dist/js/chunk-2d0aa579.82a73ddc.js" rel="prefetch"><link href="dist/js/chunk-2d0aa978.84fc06da.js" rel="prefetch"><link href="dist/js/chunk-2d0ab10b.a0694d8e.js" rel="prefetch"><link href="dist/js/chunk-2d0abe0f.a9abff6a.js" rel="prefetch"><link href="dist/js/chunk-2d0b1c6f.e920edaa.js" rel="prefetch"><link href="dist/js/chunk-2d0b361e.d657e190.js" rel="prefetch"><link href="dist/js/chunk-2d0b91e5.433fdc5c.js" rel="prefetch"><link href="dist/js/chunk-2d0b92c3.9d7f8382.js" rel="prefetch"><link href="dist/js/chunk-2d0ba309.663e66c7.js" rel="prefetch"><link href="dist/js/chunk-2d0bd54e.906e86ec.js" rel="prefetch"><link href="dist/js/chunk-2d0be174.0cf53d60.js" rel="prefetch"><link href="dist/js/chunk-2d0c0a44.0f9ebf1b.js" rel="prefetch"><link href="dist/js/chunk-2d0c14fc.7163274e.js" rel="prefetch"><link href="dist/js/chunk-2d0c18d8.2e6ddc70.js" rel="prefetch"><link href="dist/js/chunk-2d0c191e.f425dd57.js" rel="prefetch"><link href="dist/js/chunk-2d0c1a01.e37b19a2.js" rel="prefetch"><link href="dist/js/chunk-2d0c20be.206d53f0.js" rel="prefetch"><link href="dist/js/chunk-2d0d5cb9.b2fd1672.js" rel="prefetch"><link href="dist/js/chunk-2d0d9fbc.236656ce.js" rel="prefetch"><link href="dist/js/chunk-2d0da701.80759043.js" rel="prefetch"><link href="dist/js/chunk-2d0dad5f.2ecb3b60.js" rel="prefetch"><link href="dist/js/chunk-2d0db0f2.b5ce4946.js" rel="prefetch"><link href="dist/js/chunk-2d0dddce.3eea98de.js" rel="prefetch"><link href="dist/js/chunk-2d0ddf37.6ecb5986.js" rel="prefetch"><link href="dist/js/chunk-2d0de01b.a2a047cf.js" rel="prefetch"><link href="dist/js/chunk-2d0e2326.cfbc28b0.js" rel="prefetch"><link href="dist/js/chunk-2d0e268c.ed75c510.js" rel="prefetch"><link href="dist/js/chunk-2d0e5089.10135360.js" rel="prefetch"><link href="dist/js/chunk-2d0e9742.9abceada.js" rel="prefetch"><link href="dist/js/chunk-2d0f026c.044cbf6f.js" rel="prefetch"><link href="dist/js/chunk-2d2082b9.f52387a2.js" rel="prefetch"><link href="dist/js/chunk-2d208ffa.9a21f014.js" rel="prefetch"><link href="dist/js/chunk-2d20ec02.917aff76.js" rel="prefetch"><link href="dist/js/chunk-2d20f68f.ff46a11f.js" rel="prefetch"><link href="dist/js/chunk-2d210a7a.6a4911c4.js" rel="prefetch"><link href="dist/js/chunk-2d216004.704073c5.js" rel="prefetch"><link href="dist/js/chunk-2d217907.32a00939.js" rel="prefetch"><link href="dist/js/chunk-2d226d0a.6b1238d2.js" rel="prefetch"><link href="dist/js/chunk-2d2299c3.8f3151dd.js" rel="prefetch"><link href="dist/js/chunk-2d22bd06.29ee05f7.js" rel="prefetch"><link href="dist/js/chunk-2d2308b0.2797f6b4.js" rel="prefetch"><link href="dist/js/chunk-2d238428.7c9ae7c7.js" rel="prefetch"><link href="dist/js/chunk-3a2f3e67.13278516.js" rel="prefetch"><link href="dist/css/app.bed23c8e.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.c097b26d.css" rel="preload" as="style"><link href="dist/js/app.12d5802b.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.f9723ab8.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.c097b26d.css" rel="stylesheet"><link href="dist/css/app.bed23c8e.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="dist/js/chunk-vendors.f9723ab8.js"></script><script src="dist/js/app.12d5802b.js"></script></body></html>
|
||||
BIN
qrcode.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
@@ -900,6 +900,17 @@ const data5 = {
|
||||
}
|
||||
}
|
||||
|
||||
// 富文本数据v0.4.0+,需要使用RichText插件才支持富文本编辑
|
||||
const richTextData = {
|
||||
"root": {
|
||||
"data": {
|
||||
"text": "<a href='http://lxqnsys.com/' target='_blank'>理想去年实验室</a>",
|
||||
"richText": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
}
|
||||
|
||||
const rootData = {
|
||||
"root": {
|
||||
"data": {
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
"isActive": false
|
||||
},
|
||||
"children": []
|
||||
}, {
|
||||
"data": {
|
||||
"text": "<a href='http://lxqnsys.com/' target='_blank'>理想去年实验室</a>",
|
||||
"richText": true
|
||||
},
|
||||
"children": []
|
||||
}]
|
||||
}]
|
||||
},
|
||||
|
||||
@@ -59,7 +59,16 @@ const defaultOpt = {
|
||||
opacity: 0.5,
|
||||
fontSize: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
// 达到该宽度文本自动换行
|
||||
textAutoWrapWidth: 500,
|
||||
// 自定义鼠标滚轮事件处理
|
||||
// 可以传一个函数,回调参数为事件对象
|
||||
customHandleMousewheel: null,
|
||||
// 鼠标滚动的行为,如果customHandleMousewheel传了自定义函数,这个属性不生效
|
||||
mousewheelAction: 'zoom',// zoom(放大缩小)、move(上下移动)
|
||||
// 当mousewheelAction设为move时,可以通过该属性控制鼠标滚动一下视图移动的步长,单位px
|
||||
mousewheelMoveStep: 100
|
||||
}
|
||||
|
||||
// 思维导图
|
||||
@@ -118,9 +127,7 @@ class MindMap {
|
||||
|
||||
// 注册插件
|
||||
MindMap.pluginList.forEach((plugin) => {
|
||||
this[plugin.instanceName] = new plugin({
|
||||
mindMap: this
|
||||
})
|
||||
this.initPlugin(plugin)
|
||||
})
|
||||
|
||||
// 初始渲染
|
||||
@@ -142,21 +149,21 @@ class MindMap {
|
||||
}
|
||||
|
||||
// 渲染,部分渲染
|
||||
render() {
|
||||
render(callback) {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.initTheme()
|
||||
this.renderer.reRender = false
|
||||
this.renderer.render()
|
||||
this.renderer.render(callback)
|
||||
})
|
||||
}
|
||||
|
||||
// 重新渲染
|
||||
reRender() {
|
||||
reRender(callback) {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.draw.clear()
|
||||
this.initTheme()
|
||||
this.renderer.reRender = true
|
||||
this.renderer.render()
|
||||
this.renderer.render(callback)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -344,7 +351,17 @@ class MindMap {
|
||||
// 把实际内容变换
|
||||
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
|
||||
// 克隆一份数据
|
||||
const clone = svg.clone()
|
||||
let clone = svg.clone()
|
||||
// 如果实际图形宽高超出了屏幕宽高,且存在水印的话需要重新绘制水印,否则会出现超出部分没有水印的问题
|
||||
if ((rect.width > origWidth || rect.height > origHeight) && this.watermark && this.watermark.hasWatermark()) {
|
||||
this.width = rect.width
|
||||
this.height = rect.height
|
||||
this.watermark.draw()
|
||||
clone = svg.clone()
|
||||
this.width = origWidth
|
||||
this.height = origHeight
|
||||
this.watermark.draw()
|
||||
}
|
||||
// 恢复原先的大小和变换信息
|
||||
svg.size(origWidth, origHeight)
|
||||
draw.transform(origTransform)
|
||||
@@ -362,14 +379,51 @@ class MindMap {
|
||||
scaleY: origTransform.scaleY // 思维导图图形的垂直缩放值
|
||||
}
|
||||
}
|
||||
|
||||
// 添加插件
|
||||
addPlugin(plugin, opt) {
|
||||
let index = MindMap.hasPlugin(plugin)
|
||||
if (index === -1) {
|
||||
MindMap.usePlugin(plugin, opt)
|
||||
this.initPlugin(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除插件
|
||||
removePlugin(plugin) {
|
||||
let index = MindMap.hasPlugin(plugin)
|
||||
if (index !== -1) {
|
||||
MindMap.pluginList.splice(index, 1)
|
||||
if (this[plugin.instanceName]) {
|
||||
if (this[plugin.instanceName].beforePluginRemove) {
|
||||
this[plugin.instanceName].beforePluginRemove()
|
||||
}
|
||||
delete this[plugin.instanceName]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实例化插件
|
||||
initPlugin(plugin) {
|
||||
this[plugin.instanceName] = new plugin({
|
||||
mindMap: this,
|
||||
pluginOpt: plugin.pluginOpt
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 插件列表
|
||||
MindMap.pluginList = []
|
||||
MindMap.usePlugin = (plugin) => {
|
||||
MindMap.usePlugin = (plugin, opt = {}) => {
|
||||
plugin.pluginOpt = opt
|
||||
MindMap.pluginList.push(plugin)
|
||||
return MindMap
|
||||
}
|
||||
MindMap.hasPlugin = (plugin) => {
|
||||
return MindMap.pluginList.findIndex((item) => {
|
||||
return item === plugin
|
||||
})
|
||||
}
|
||||
|
||||
// 定义新主题
|
||||
MindMap.defineTheme = (name, config = {}) => {
|
||||
|
||||
465
simple-mind-map/package-lock.json
generated
@@ -1,19 +1,22 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.2.21",
|
||||
"version": "0.4.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "0.2.21",
|
||||
"version": "0.4.5",
|
||||
"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",
|
||||
"jspdf": "^2.5.1",
|
||||
"jszip": "^3.10.1",
|
||||
"quill": "^1.3.6",
|
||||
"uuid": "^9.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -225,7 +228,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
@@ -251,6 +253,18 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -294,6 +308,14 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -351,7 +373,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
@@ -373,6 +394,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deep-equal": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
|
||||
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
|
||||
"dependencies": {
|
||||
"is-arguments": "^1.0.4",
|
||||
"is-date-object": "^1.0.1",
|
||||
"is-regex": "^1.0.4",
|
||||
"object-is": "^1.0.1",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -387,6 +424,21 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
|
||||
"integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
|
||||
"dependencies": {
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@@ -586,12 +638,22 @@
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
@@ -671,6 +733,32 @@
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
|
||||
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@@ -724,6 +812,17 @@
|
||||
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@@ -733,11 +832,46 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
|
||||
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
@@ -800,6 +934,35 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-date-object": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
||||
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -830,6 +993,21 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-regex": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
@@ -969,6 +1147,29 @@
|
||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@@ -1030,6 +1231,11 @@
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"node_modules/parchment": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -1132,6 +1338,37 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/quill": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz",
|
||||
"integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==",
|
||||
"dependencies": {
|
||||
"clone": "^2.1.1",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"extend": "^3.0.1",
|
||||
"parchment": "^1.1.4",
|
||||
"quill-delta": "^3.6.2"
|
||||
}
|
||||
},
|
||||
"node_modules/quill-delta": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||
"dependencies": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"extend": "^3.0.2",
|
||||
"fast-diff": "1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/quill/node_modules/eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
@@ -1159,6 +1396,22 @@
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
|
||||
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"functions-have-names": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regexpp": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
|
||||
@@ -1336,7 +1589,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
@@ -1389,11 +1641,18 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -1593,8 +1852,7 @@
|
||||
"base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"optional": true
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
@@ -1611,6 +1869,15 @@
|
||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -1642,6 +1909,11 @@
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -1688,7 +1960,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
@@ -1702,6 +1973,19 @@
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
|
||||
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
|
||||
"requires": {
|
||||
"is-arguments": "^1.0.4",
|
||||
"is-date-object": "^1.0.1",
|
||||
"is-regex": "^1.0.4",
|
||||
"object-is": "^1.0.1",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -1713,6 +1997,15 @@
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz",
|
||||
"integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ=="
|
||||
},
|
||||
"define-properties": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
|
||||
"integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
|
||||
"requires": {
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@@ -1860,12 +2153,22 @@
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
@@ -1933,6 +2236,26 @@
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"dev": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
|
||||
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@@ -1971,17 +2294,45 @@
|
||||
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
|
||||
"dev": true
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"has-property-descriptors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
|
||||
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
|
||||
"requires": {
|
||||
"get-intrinsic": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
@@ -2029,6 +2380,23 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-date-object": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
||||
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
|
||||
"requires": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -2050,6 +2418,15 @@
|
||||
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
@@ -2168,6 +2545,20 @@
|
||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"dev": true
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@@ -2214,6 +2605,11 @@
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"parchment": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -2275,6 +2671,36 @@
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true
|
||||
},
|
||||
"quill": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz",
|
||||
"integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==",
|
||||
"requires": {
|
||||
"clone": "^2.1.1",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"extend": "^3.0.1",
|
||||
"parchment": "^1.1.4",
|
||||
"quill-delta": "^3.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"eventemitter3": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"quill-delta": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||
"requires": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"extend": "^3.0.2",
|
||||
"fast-diff": "1.1.2"
|
||||
}
|
||||
},
|
||||
"raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
@@ -2302,6 +2728,16 @@
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"regexp.prototype.flags": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
|
||||
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"functions-have-names": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"regexpp": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
|
||||
@@ -2419,7 +2855,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
@@ -2463,11 +2898,15 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.5",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
@@ -28,8 +28,11 @@
|
||||
"canvg": "^3.0.7",
|
||||
"deepmerge": "^1.5.2",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"jszip": "^3.10.1",
|
||||
"quill": "^1.3.6",
|
||||
"uuid": "^9.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
386
simple-mind-map/src/AssociativeLine.js
Normal file
@@ -0,0 +1,386 @@
|
||||
import { walk, bfsWalk, throttle } from './utils/'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
// 关联线类
|
||||
class AssociativeLine {
|
||||
constructor(opt = {}) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.draw = this.mindMap.draw
|
||||
// 当前所有连接线
|
||||
this.lineList = []
|
||||
// 当前激活的连接线
|
||||
this.activeLine = null
|
||||
// 当前正在创建连接线
|
||||
this.isCreatingLine = false // 是否正在创建连接线中
|
||||
this.creatingStartNode = null // 起始节点
|
||||
this.creatingLine = null // 创建过程中的连接线
|
||||
this.overlapNode = null // 创建过程中的目标节点
|
||||
// 是否有节点正在被拖拽
|
||||
this.isNodeDragging = false
|
||||
// 箭头图标
|
||||
this.markerPath = null
|
||||
this.marker = this.createMarker()
|
||||
// 节流一下,不然很卡
|
||||
this.checkOverlapNode = throttle(this.checkOverlapNode, 100, this)
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 监听事件
|
||||
bindEvent() {
|
||||
// 节点树渲染完毕后渲染连接线
|
||||
this.renderAllLines = this.renderAllLines.bind(this)
|
||||
this.mindMap.on('node_tree_render_end', this.renderAllLines)
|
||||
// 状态改变后重新渲染连接线
|
||||
this.mindMap.on('data_change', this.renderAllLines)
|
||||
// 监听画布和节点点击事件,用于清除当前激活的连接线
|
||||
this.mindMap.on('draw_click', () => {
|
||||
this.clearActiveLine()
|
||||
})
|
||||
this.mindMap.on('node_click', node => {
|
||||
if (this.isCreatingLine) {
|
||||
this.completeCreateLine(node)
|
||||
} else {
|
||||
this.clearActiveLine()
|
||||
}
|
||||
})
|
||||
// 注册删除快捷键
|
||||
this.mindMap.keyCommand.addShortcut(
|
||||
'Del|Backspace',
|
||||
this.removeLine.bind(this)
|
||||
)
|
||||
// 注册添加连接线的命令
|
||||
this.mindMap.command.add('ADD_ASSOCIATIVE_LINE', this.addLine.bind(this))
|
||||
// 监听鼠标移动事件
|
||||
this.mindMap.on('mousemove', this.onMousemove.bind(this))
|
||||
// 节点拖拽事件
|
||||
this.mindMap.on('node_dragging', this.onNodeDragging.bind(this))
|
||||
this.mindMap.on('node_dragend', this.onNodeDragend.bind(this))
|
||||
}
|
||||
|
||||
// 创建箭头
|
||||
createMarker() {
|
||||
return this.draw.marker(20, 20, add => {
|
||||
add.ref(2, 5)
|
||||
add.size(10, 10)
|
||||
add.attr('orient', 'auto-start-reverse')
|
||||
this.markerPath = add.path('M0,0 L2,5 L0,10 L10,5 Z')
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染所有连线
|
||||
renderAllLines() {
|
||||
this.removeAllLines()
|
||||
let tree = this.mindMap.renderer.root
|
||||
if (!tree) return
|
||||
let idToNode = new Map()
|
||||
let nodeToIds = new Map()
|
||||
walk(
|
||||
tree,
|
||||
null,
|
||||
cur => {
|
||||
if (!cur) return
|
||||
let data = cur.nodeData.data
|
||||
if (
|
||||
data.associativeLineTargets &&
|
||||
data.associativeLineTargets.length > 0
|
||||
) {
|
||||
nodeToIds.set(cur, data.associativeLineTargets)
|
||||
}
|
||||
if (data.id) {
|
||||
idToNode.set(data.id, cur)
|
||||
}
|
||||
},
|
||||
() => {},
|
||||
true,
|
||||
0
|
||||
)
|
||||
nodeToIds.forEach((ids, node) => {
|
||||
ids.forEach(id => {
|
||||
let toNode = idToNode.get(id)
|
||||
if (!node || !toNode) return
|
||||
let [startPoint, endPoint] = this.computeNodePoints(node, toNode)
|
||||
this.drawLine(startPoint, endPoint, node, toNode)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 绘制连接线
|
||||
drawLine(startPoint, endPoint, node, toNode) {
|
||||
let { associativeLineWidth, associativeLineColor, associativeLineActiveWidth, associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
// 箭头
|
||||
this.markerPath.stroke({ color: associativeLineColor }).fill({ color: associativeLineColor })
|
||||
// 路径
|
||||
let pathStr = this.cubicBezierPath(
|
||||
startPoint.x,
|
||||
startPoint.y,
|
||||
endPoint.x,
|
||||
endPoint.y
|
||||
)
|
||||
// 虚线
|
||||
let path = this.draw.path()
|
||||
path
|
||||
.stroke({ width: associativeLineWidth, color: associativeLineColor, dasharray: [6, 4] })
|
||||
.fill({ color: 'none' })
|
||||
path.plot(pathStr)
|
||||
path.marker('end', this.marker)
|
||||
// 不可见的点击线
|
||||
let clickPath = this.draw.path()
|
||||
clickPath.stroke({ width: associativeLineActiveWidth, color: 'transparent' }).fill({ color: 'none' })
|
||||
clickPath.plot(pathStr)
|
||||
clickPath.click(e => {
|
||||
e.stopPropagation()
|
||||
this.clearActiveNodes()
|
||||
this.clearActiveLine()
|
||||
this.activeLine = [path, clickPath, node, toNode]
|
||||
clickPath.stroke({ color: associativeLineActiveColor })
|
||||
this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
|
||||
})
|
||||
this.lineList.push([path, clickPath, node, toNode])
|
||||
}
|
||||
|
||||
// 移除所有连接线
|
||||
removeAllLines() {
|
||||
this.lineList.forEach(line => {
|
||||
line[0].remove()
|
||||
line[1].remove()
|
||||
})
|
||||
this.lineList = []
|
||||
}
|
||||
|
||||
// 从当前激活节点开始创建连接线
|
||||
createLineFromActiveNode() {
|
||||
if (this.mindMap.renderer.activeNodeList.length <= 0) return
|
||||
let node = this.mindMap.renderer.activeNodeList[0]
|
||||
this.createLine(node)
|
||||
}
|
||||
|
||||
// 创建连接线
|
||||
createLine(fromNode) {
|
||||
let { associativeLineWidth, associativeLineColor } = this.mindMap.themeConfig
|
||||
if (this.isCreatingLine || !fromNode) return
|
||||
this.isCreatingLine = true
|
||||
this.creatingStartNode = fromNode
|
||||
this.creatingLine = this.draw.path()
|
||||
this.creatingLine
|
||||
.stroke({ width: associativeLineWidth, color: associativeLineColor, dasharray: [6, 4] })
|
||||
.fill({ color: 'none' })
|
||||
this.creatingLine.marker('end', this.marker)
|
||||
}
|
||||
|
||||
// 鼠标移动事件
|
||||
onMousemove(e) {
|
||||
if (!this.isCreatingLine) return
|
||||
this.updateCreatingLine(e)
|
||||
}
|
||||
|
||||
// 更新创建过程中的连接线
|
||||
updateCreatingLine(e) {
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
let { scaleX, scaleY, translateX, translateY } =
|
||||
this.mindMap.draw.transform()
|
||||
x = (x - translateX) / scaleX
|
||||
y = (y - translateY) / scaleY
|
||||
let startPoint = this.getNodePoint(this.creatingStartNode)
|
||||
let pathStr = this.cubicBezierPath(startPoint.x, startPoint.y, x, y)
|
||||
this.creatingLine.plot(pathStr)
|
||||
this.checkOverlapNode(x, y)
|
||||
}
|
||||
|
||||
// 检测当前移动到的目标节点
|
||||
checkOverlapNode(x, y) {
|
||||
this.overlapNode = null
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(node, false)
|
||||
}
|
||||
if (node === this.creatingStartNode || this.overlapNode) {
|
||||
return
|
||||
}
|
||||
let { left, top, width, height } = node
|
||||
let right = left + width
|
||||
let bottom = top + height
|
||||
if (x >= left && x <= right && y >= top && y <= bottom) {
|
||||
this.overlapNode = node
|
||||
}
|
||||
})
|
||||
if (this.overlapNode && !this.overlapNode.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, true)
|
||||
}
|
||||
}
|
||||
|
||||
// 完成创建连接线
|
||||
completeCreateLine(node) {
|
||||
if (this.creatingStartNode === node) return
|
||||
this.addLine(this.creatingStartNode, node)
|
||||
if (this.overlapNode && this.overlapNode.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||
}
|
||||
this.isCreatingLine = false
|
||||
this.creatingStartNode = null
|
||||
this.creatingLine.remove()
|
||||
this.creatingLine = null
|
||||
this.overlapNode = null
|
||||
}
|
||||
|
||||
// 添加连接线
|
||||
addLine(fromNode, toNode) {
|
||||
if (!fromNode || !toNode) return
|
||||
let id = toNode.nodeData.data.id
|
||||
if (!id) {
|
||||
id = uuid()
|
||||
this.mindMap.execCommand('SET_NODE_DATA', toNode, {
|
||||
id
|
||||
})
|
||||
}
|
||||
let list = fromNode.nodeData.data.associativeLineTargets || []
|
||||
list.push(id)
|
||||
this.mindMap.execCommand('SET_NODE_DATA', fromNode, {
|
||||
associativeLineTargets: list
|
||||
})
|
||||
}
|
||||
|
||||
// 删除连接线
|
||||
removeLine() {
|
||||
if (!this.activeLine) return
|
||||
let [, , node, toNode] = this.activeLine
|
||||
let id = toNode.nodeData.data.id
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
associativeLineTargets: node.nodeData.data.associativeLineTargets.filter(
|
||||
item => {
|
||||
return item !== id
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// 清除当前激活的节点
|
||||
clearActiveNodes() {
|
||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
||||
}
|
||||
}
|
||||
|
||||
// 清除激活的线
|
||||
clearActiveLine() {
|
||||
if (this.activeLine) {
|
||||
this.activeLine[1].stroke({
|
||||
color: 'transparent'
|
||||
})
|
||||
this.activeLine = null
|
||||
}
|
||||
}
|
||||
|
||||
// 处理节点正在拖拽事件
|
||||
onNodeDragging() {
|
||||
if (this.isNodeDragging) return
|
||||
this.isNodeDragging = true
|
||||
this.lineList.forEach(line => {
|
||||
line[0].hide()
|
||||
line[1].hide()
|
||||
})
|
||||
}
|
||||
|
||||
// 处理节点拖拽完成事件
|
||||
onNodeDragend() {
|
||||
if (!this.isNodeDragging) return
|
||||
this.lineList.forEach(line => {
|
||||
line[0].show()
|
||||
line[1].show()
|
||||
})
|
||||
this.isNodeDragging = false
|
||||
}
|
||||
|
||||
// 三次贝塞尔曲线
|
||||
cubicBezierPath(x1, y1, x2, y2) {
|
||||
let cx1 = x1 + (x2 - x1) / 2
|
||||
let cy1 = y1
|
||||
let cx2 = cx1
|
||||
let cy2 = y2
|
||||
if (Math.abs(x1 - x2) <= 5) {
|
||||
cx1 = x1 + (y2 - y1) / 2
|
||||
cx2 = cx1
|
||||
}
|
||||
return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}`
|
||||
}
|
||||
|
||||
// 根据两个节点的位置计算节点的连接点
|
||||
computeNodePoints(fromNode, toNode) {
|
||||
let fromRect = this.getNodeRect(fromNode)
|
||||
let fromCx = (fromRect.right + fromRect.left) / 2
|
||||
let fromCy = (fromRect.bottom + fromRect.top) / 2
|
||||
let toRect = this.getNodeRect(toNode)
|
||||
let toCx = (toRect.right + toRect.left) / 2
|
||||
let toCy = (toRect.bottom + toRect.top) / 2
|
||||
// 中心点坐标的差值
|
||||
let offsetX = toCx - fromCx
|
||||
let offsetY = toCy - fromCy
|
||||
if (offsetX === 0 && offsetY === 0) return
|
||||
let fromDir = ''
|
||||
let toDir = ''
|
||||
if (offsetX <= 0 && offsetX <= offsetY && offsetX <= -offsetY) {
|
||||
// left
|
||||
fromDir = 'left'
|
||||
toDir = 'right'
|
||||
} else if (offsetX > 0 && offsetX >= -offsetY && offsetX >= offsetY) {
|
||||
// right
|
||||
fromDir = 'right'
|
||||
toDir = 'left'
|
||||
} else if (offsetY <= 0 && offsetY < offsetX && offsetY < -offsetX) {
|
||||
// up
|
||||
fromDir = 'top'
|
||||
toDir = 'bottom'
|
||||
} else if (offsetY > 0 && -offsetY < offsetX && offsetY > offsetX) {
|
||||
// down
|
||||
fromDir = 'bottom'
|
||||
toDir = 'top'
|
||||
}
|
||||
return [
|
||||
this.getNodePoint(fromNode, fromDir),
|
||||
this.getNodePoint(toNode, toDir)
|
||||
]
|
||||
}
|
||||
|
||||
// 获取节点的位置信息
|
||||
getNodeRect(node) {
|
||||
let { left, top, width, height } = node
|
||||
return {
|
||||
right: left + width,
|
||||
bottom: top + height,
|
||||
left,
|
||||
top
|
||||
}
|
||||
}
|
||||
|
||||
// 获取节点的连接点
|
||||
getNodePoint(node, dir = 'right') {
|
||||
let { left, top, width, height } = node
|
||||
switch (dir) {
|
||||
case 'left':
|
||||
return {
|
||||
x: left,
|
||||
y: top + height / 2
|
||||
}
|
||||
case 'right':
|
||||
return {
|
||||
x: left + width,
|
||||
y: top + height / 2
|
||||
}
|
||||
case 'top':
|
||||
return {
|
||||
x: left + width / 2,
|
||||
y: top
|
||||
}
|
||||
case 'bottom':
|
||||
return {
|
||||
x: left + width / 2,
|
||||
y: top + height
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssociativeLine.instanceName = 'associativeLine'
|
||||
|
||||
export default AssociativeLine
|
||||
@@ -98,7 +98,9 @@ class Command {
|
||||
this.activeHistoryIndex,
|
||||
this.history.length
|
||||
)
|
||||
return simpleDeepClone(this.history[this.activeHistoryIndex])
|
||||
let data = simpleDeepClone(this.history[this.activeHistoryIndex])
|
||||
this.mindMap.emit('data_change', data)
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +113,9 @@ class Command {
|
||||
if (this.activeHistoryIndex + step <= len - 1) {
|
||||
this.activeHistoryIndex += step
|
||||
this.mindMap.emit('back_forward', this.activeHistoryIndex)
|
||||
return simpleDeepClone(this.history[this.activeHistoryIndex])
|
||||
let data = simpleDeepClone(this.history[this.activeHistoryIndex])
|
||||
this.mindMap.emit('data_change', data)
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ class Drag extends Base {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.mindMap.emit('node_dragging', this.node)
|
||||
e.preventDefault()
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.mouseMoveX = x
|
||||
@@ -136,6 +137,7 @@ class Drag extends Base {
|
||||
this.mindMap.render()
|
||||
}
|
||||
this.reset()
|
||||
this.mindMap.emit('node_dragend')
|
||||
}
|
||||
|
||||
// 创建克隆节点
|
||||
|
||||
@@ -43,12 +43,7 @@ class Event extends EventEmitter {
|
||||
this.mindMap.svg.on('mousedown', this.onSvgMousedown)
|
||||
window.addEventListener('mousemove', this.onMousemove)
|
||||
window.addEventListener('mouseup', this.onMouseup)
|
||||
// 兼容火狐浏览器
|
||||
if (window.navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
|
||||
this.mindMap.el.addEventListener('DOMMouseScroll', this.onMousewheel)
|
||||
} else {
|
||||
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
||||
}
|
||||
this.mindMap.el.addEventListener('wheel', this.onMousewheel)
|
||||
this.mindMap.svg.on('contextmenu', this.onContextmenu)
|
||||
window.addEventListener('keyup', this.onKeyup)
|
||||
}
|
||||
@@ -59,7 +54,7 @@ class Event extends EventEmitter {
|
||||
this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
|
||||
window.removeEventListener('mousemove', this.onMousemove)
|
||||
window.removeEventListener('mouseup', this.onMouseup)
|
||||
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
||||
this.mindMap.el.removeEventListener('wheel', this.onMousewheel)
|
||||
this.mindMap.svg.off('contextmenu', this.onContextmenu)
|
||||
window.removeEventListener('keyup', this.onKeyup)
|
||||
}
|
||||
@@ -110,10 +105,17 @@ class Event extends EventEmitter {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
let dir
|
||||
if ((e.wheelDeltaY || e.detail) > 0) {
|
||||
dir = 'up'
|
||||
// 解决mac触控板双指缩放方向相反的问题
|
||||
if (e.ctrlKey) {
|
||||
if (e.deltaY > 0) dir = 'up'
|
||||
if (e.deltaY < 0) dir = 'down'
|
||||
if (e.deltaX > 0) dir = 'left'
|
||||
if (e.deltaX < 0) dir = 'right'
|
||||
} else {
|
||||
dir = 'down'
|
||||
if ((e.wheelDeltaY || e.detail) > 0) dir = 'up'
|
||||
if ((e.wheelDeltaY || e.detail) < 0) dir = 'down'
|
||||
if ((e.wheelDeltaX || e.detail) > 0) dir = 'left'
|
||||
if ((e.wheelDeltaX || e.detail) < 0) dir = 'right'
|
||||
}
|
||||
this.emit('mousewheel', e, dir, this)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Export {
|
||||
}
|
||||
|
||||
// 获取svg数据
|
||||
async getSvgData() {
|
||||
async getSvgData(domToImage) {
|
||||
let { svg, svgHTML } = this.mindMap.getSvgData()
|
||||
// 把图片的url转换成data:url类型,否则导出会丢失图片
|
||||
let imageList = svg.find('image')
|
||||
@@ -36,9 +36,17 @@ class Export {
|
||||
item.attr('href', imgData)
|
||||
})
|
||||
await Promise.all(task)
|
||||
// 如果开启了富文本编辑,需要把svg中的dom元素转换成图片
|
||||
let nodeWithDomToImg = null
|
||||
if (domToImage && this.mindMap.richText) {
|
||||
let res = await this.mindMap.richText.handleSvgDomElements(svg)
|
||||
nodeWithDomToImg = res.svg
|
||||
svgHTML = res.svgHTML
|
||||
}
|
||||
return {
|
||||
node: svg,
|
||||
str: svgHTML
|
||||
str: svgHTML,
|
||||
nodeWithDomToImg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +131,7 @@ class Export {
|
||||
* 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
|
||||
*/
|
||||
async png() {
|
||||
let { str } = await this.getSvgData()
|
||||
let { str } = await this.getSvgData(true)
|
||||
// 转换成blob数据
|
||||
let blob = new Blob([str], {
|
||||
type: 'image/svg+xml'
|
||||
@@ -191,8 +199,21 @@ class Export {
|
||||
}
|
||||
|
||||
// 导出为svg
|
||||
async svg(name) {
|
||||
let { node } = await this.getSvgData()
|
||||
// domToImage:是否将svg中的dom节点转换成图片的形式
|
||||
// plusCssText:附加的css样式,如果svg中存在dom节点,想要设置一些针对节点的样式可以通过这个参数传入
|
||||
async svg(name, domToImage = false, plusCssText) {
|
||||
let { node, nodeWithDomToImg } = await this.getSvgData(domToImage)
|
||||
// 开启了节点富文本编辑
|
||||
if (this.mindMap.richText) {
|
||||
if (domToImage) {
|
||||
node = nodeWithDomToImg
|
||||
} else if (plusCssText) {
|
||||
let foreignObjectList = node.find('foreignObject')
|
||||
if (foreignObjectList.length > 0) {
|
||||
foreignObjectList[0].add(SVG(`<style>${plusCssText}</style>`))
|
||||
}
|
||||
}
|
||||
}
|
||||
node.first().before(SVG(`<title>${name}</title>`))
|
||||
await this.drawBackgroundToSvg(node)
|
||||
let str = node.svg()
|
||||
|
||||
@@ -239,7 +239,7 @@ class Render {
|
||||
|
||||
// 渲染
|
||||
|
||||
render() {
|
||||
render(callback = () => {}) {
|
||||
if (this.reRender) {
|
||||
this.clearActive()
|
||||
}
|
||||
@@ -247,6 +247,7 @@ class Render {
|
||||
this.root = root
|
||||
this.root.render(() => {
|
||||
this.mindMap.emit('node_tree_render_end')
|
||||
callback()
|
||||
})
|
||||
})
|
||||
this.mindMap.emit('node_active', null, this.activeNodeList)
|
||||
@@ -472,6 +473,8 @@ class Render {
|
||||
if (node.isRoot) {
|
||||
return
|
||||
}
|
||||
// 如果是二级节点变成了下级节点,或是下级节点变成了二级节点,节点样式需要更新
|
||||
let nodeLayerChanged = (node.layerIndex === 1 && exist.layerIndex !== 1) || (node.layerIndex !== 1 && exist.layerIndex === 1)
|
||||
// 移动节点
|
||||
let nodeParent = node.parent
|
||||
let nodeBorthers = nodeParent.children
|
||||
@@ -495,7 +498,12 @@ class Render {
|
||||
}
|
||||
existBorthers.splice(existIndex, 0, node)
|
||||
existParent.nodeData.children.splice(existIndex, 0, node.nodeData)
|
||||
this.mindMap.render()
|
||||
this.mindMap.render(() => {
|
||||
if (nodeLayerChanged) {
|
||||
node.getSize()
|
||||
node.renderNode()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 将节点移动到另一个节点的后面
|
||||
@@ -504,6 +512,8 @@ class Render {
|
||||
if (node.isRoot) {
|
||||
return
|
||||
}
|
||||
// 如果是二级节点变成了下级节点,或是下级节点变成了二级节点,节点样式需要更新
|
||||
let nodeLayerChanged = (node.layerIndex === 1 && exist.layerIndex !== 1) || (node.layerIndex !== 1 && exist.layerIndex === 1)
|
||||
// 移动节点
|
||||
let nodeParent = node.parent
|
||||
let nodeBorthers = nodeParent.children
|
||||
@@ -528,7 +538,12 @@ class Render {
|
||||
existIndex++
|
||||
existBorthers.splice(existIndex, 0, node)
|
||||
existParent.nodeData.children.splice(existIndex, 0, node.nodeData)
|
||||
this.mindMap.render()
|
||||
this.mindMap.render(() => {
|
||||
if (nodeLayerChanged) {
|
||||
node.getSize()
|
||||
node.renderNode()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 移除节点
|
||||
@@ -537,29 +552,35 @@ class Render {
|
||||
if (this.activeNodeList.length <= 0) {
|
||||
return
|
||||
}
|
||||
for (let i = 0; i < this.activeNodeList.length; i++) {
|
||||
let node = this.activeNodeList[i]
|
||||
if (node.isGeneralization) {
|
||||
// 删除概要节点
|
||||
this.setNodeData(node.generalizationBelongNode, {
|
||||
generalization: null
|
||||
})
|
||||
node.generalizationBelongNode.update()
|
||||
this.removeActiveNode(node)
|
||||
i--
|
||||
} else if (node.isRoot) {
|
||||
node.children.forEach(child => {
|
||||
child.remove()
|
||||
})
|
||||
node.children = []
|
||||
node.nodeData.children = []
|
||||
break
|
||||
} else {
|
||||
this.removeActiveNode(node)
|
||||
this.removeOneNode(node)
|
||||
i--
|
||||
let root = this.activeNodeList.find((node) => {
|
||||
return node.isRoot
|
||||
})
|
||||
if (root) {
|
||||
this.clearActive()
|
||||
root.children.forEach(child => {
|
||||
child.remove()
|
||||
})
|
||||
root.children = []
|
||||
root.nodeData.children = []
|
||||
} else {
|
||||
for (let i = 0; i < this.activeNodeList.length; i++) {
|
||||
let node = this.activeNodeList[i]
|
||||
if (node.isGeneralization) {
|
||||
// 删除概要节点
|
||||
this.setNodeData(node.generalizationBelongNode, {
|
||||
generalization: null
|
||||
})
|
||||
node.generalizationBelongNode.update()
|
||||
this.removeActiveNode(node)
|
||||
i--
|
||||
} else {
|
||||
this.removeActiveNode(node)
|
||||
this.removeOneNode(node)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
this.activeNodeList = []
|
||||
this.mindMap.emit('node_active', null, [])
|
||||
this.mindMap.render()
|
||||
}
|
||||
@@ -647,6 +668,15 @@ class Render {
|
||||
[prop]: value
|
||||
}
|
||||
}
|
||||
// 如果开启了富文本,则需要应用到富文本上
|
||||
if (this.mindMap.richText) {
|
||||
this.mindMap.richText.showEditText(node)
|
||||
let config = this.mindMap.richText.normalStyleToRichTextStyle({
|
||||
[prop]: value
|
||||
})
|
||||
this.mindMap.richText.formatAllText(config)
|
||||
this.mindMap.richText.hideEditText()
|
||||
}
|
||||
this.setNodeDataRender(node, data)
|
||||
// 更新了连线的样式
|
||||
if (lineStyleProps.includes(prop)) {
|
||||
@@ -767,9 +797,10 @@ class Render {
|
||||
|
||||
// 设置节点文本
|
||||
|
||||
setNodeText(node, text) {
|
||||
setNodeText(node, text, richText) {
|
||||
this.setNodeDataRender(node, {
|
||||
text
|
||||
text,
|
||||
richText
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
443
simple-mind-map/src/RichText.js
Normal file
@@ -0,0 +1,443 @@
|
||||
import Quill from 'quill'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import './css/quill.css'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { Image as SvgImage } from '@svgdotjs/svg.js'
|
||||
import { walk } from './utils'
|
||||
|
||||
let extended = false
|
||||
|
||||
// 扩展quill的字体列表
|
||||
let fontFamilyList = [
|
||||
'宋体, SimSun, Songti SC',
|
||||
'微软雅黑, Microsoft YaHei',
|
||||
'楷体, 楷体_GB2312, SimKai, STKaiti',
|
||||
'黑体, SimHei, Heiti SC',
|
||||
'隶书, SimLi',
|
||||
'andale mono',
|
||||
'arial, helvetica, sans-serif',
|
||||
'arial black, avant garde',
|
||||
'comic sans ms',
|
||||
'impact, chicago',
|
||||
'times new roman',
|
||||
'sans-serif',
|
||||
'serif'
|
||||
]
|
||||
|
||||
// 扩展quill的字号列表
|
||||
let fontSizeList = new Array(100).fill(0).map((_, index) => {
|
||||
return index + 'px'
|
||||
})
|
||||
|
||||
// 节点支持富文本编辑功能
|
||||
class RichText {
|
||||
constructor({ mindMap, pluginOpt }) {
|
||||
this.mindMap = mindMap
|
||||
this.pluginOpt = pluginOpt
|
||||
this.textEditNode = null
|
||||
this.showTextEdit = false
|
||||
this.quill = null
|
||||
this.range = null
|
||||
this.lastRange = null
|
||||
this.node = null
|
||||
this.initOpt()
|
||||
this.extendQuill()
|
||||
}
|
||||
|
||||
// 处理选项参数
|
||||
initOpt() {
|
||||
if (
|
||||
this.pluginOpt.fontFamilyList &&
|
||||
Array.isArray(this.pluginOpt.fontFamilyList)
|
||||
) {
|
||||
fontFamilyList = this.pluginOpt.fontFamilyList
|
||||
}
|
||||
if (
|
||||
this.pluginOpt.fontSizeList &&
|
||||
Array.isArray(this.pluginOpt.fontSizeList)
|
||||
) {
|
||||
fontSizeList = this.pluginOpt.fontSizeList
|
||||
}
|
||||
}
|
||||
|
||||
// 扩展quill编辑器
|
||||
extendQuill() {
|
||||
if (extended) {
|
||||
return
|
||||
}
|
||||
extended = true
|
||||
|
||||
// 扩展quill的字体列表
|
||||
const FontAttributor = Quill.import('attributors/class/font')
|
||||
FontAttributor.whitelist = fontFamilyList
|
||||
Quill.register(FontAttributor, true)
|
||||
|
||||
const FontStyle = Quill.import('attributors/style/font')
|
||||
FontStyle.whitelist = fontFamilyList
|
||||
Quill.register(FontStyle, true)
|
||||
|
||||
// 扩展quill的字号列表
|
||||
const SizeAttributor = Quill.import('attributors/class/size')
|
||||
SizeAttributor.whitelist = fontSizeList
|
||||
Quill.register(SizeAttributor, true)
|
||||
|
||||
const SizeStyle = Quill.import('attributors/style/size')
|
||||
SizeStyle.whitelist = fontSizeList
|
||||
Quill.register(SizeStyle, true)
|
||||
}
|
||||
|
||||
// 显示文本编辑控件
|
||||
showEditText(node, rect) {
|
||||
if (this.showTextEdit) {
|
||||
return
|
||||
}
|
||||
this.node = node
|
||||
if (!rect) rect = node._textData.node.node.getBoundingClientRect()
|
||||
this.mindMap.emit('before_show_text_edit')
|
||||
this.mindMap.renderer.textEdit.registerTmpShortcut()
|
||||
if (!this.textEditNode) {
|
||||
this.textEditNode = document.createElement('div')
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);outline: none; word-break: break-all;`
|
||||
document.body.appendChild(this.textEditNode)
|
||||
}
|
||||
// 原始宽高
|
||||
let g = node._textData.node
|
||||
let originWidth = g.attr('data-width')
|
||||
let originHeight = g.attr('data-height')
|
||||
this.textEditNode.style.minWidth = originWidth + 'px'
|
||||
this.textEditNode.style.minHeight = originHeight + 'px'
|
||||
this.textEditNode.style.left =
|
||||
rect.left + (rect.width - originWidth) / 2 + 'px'
|
||||
this.textEditNode.style.top =
|
||||
rect.top + (rect.height - originHeight) / 2 + 'px'
|
||||
this.textEditNode.style.display = 'block'
|
||||
this.textEditNode.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + 'px'
|
||||
this.textEditNode.style.transform = `scale(${rect.width / originWidth}, ${
|
||||
rect.height / originHeight
|
||||
})`
|
||||
if (!node.nodeData.data.richText) {
|
||||
// 还不是富文本的情况
|
||||
let text = node.nodeData.data.text.split(/\n/gim).join('<br>')
|
||||
let html = `<p>${text}</p>`
|
||||
this.textEditNode.innerHTML = html
|
||||
} else {
|
||||
this.textEditNode.innerHTML = node.nodeData.data.text
|
||||
}
|
||||
this.initQuillEditor()
|
||||
document.querySelector('.ql-editor').style.minHeight = originHeight + 'px'
|
||||
this.showTextEdit = true
|
||||
this.selectAll()
|
||||
if (!node.nodeData.data.richText) {
|
||||
// 如果是非富文本的情况,需要手动应用文本样式
|
||||
this.setTextStyleIfNotRichText(node)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是非富文本的情况,需要手动应用文本样式
|
||||
setTextStyleIfNotRichText(node) {
|
||||
let style = {
|
||||
font: node.style.merge('fontFamily'),
|
||||
color: node.style.merge('color'),
|
||||
italic: node.style.merge('fontStyle') === 'italic',
|
||||
bold: node.style.merge('fontWeight') === 'bold',
|
||||
size: node.style.merge('fontSize') + 'px',
|
||||
underline: node.style.merge('textDecoration') === 'underline',
|
||||
strike: node.style.merge('textDecoration') === 'line-through'
|
||||
}
|
||||
this.formatText(style)
|
||||
}
|
||||
|
||||
// 隐藏文本编辑控件,即完成编辑
|
||||
hideEditText() {
|
||||
if (!this.showTextEdit) {
|
||||
return
|
||||
}
|
||||
let html = this.quill.container.firstChild.innerHTML
|
||||
// 去除最后的空行
|
||||
html = html.replace(/<p><br><\/p>$/, '')
|
||||
this.mindMap.renderer.activeNodeList.forEach(node => {
|
||||
this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
|
||||
if (node.isGeneralization) {
|
||||
// 概要节点
|
||||
node.generalizationBelongNode.updateGeneralization()
|
||||
}
|
||||
this.mindMap.render()
|
||||
})
|
||||
this.mindMap.emit(
|
||||
'hide_text_edit',
|
||||
this.textEditNode,
|
||||
this.mindMap.renderer.activeNodeList
|
||||
)
|
||||
this.textEditNode.style.display = 'none'
|
||||
this.showTextEdit = false
|
||||
this.mindMap.emit('rich_text_selection_change', false)
|
||||
this.node = null
|
||||
}
|
||||
|
||||
// 初始化Quill富文本编辑器
|
||||
initQuillEditor() {
|
||||
this.quill = new Quill(this.textEditNode, {
|
||||
modules: {
|
||||
toolbar: false,
|
||||
keyboard: {
|
||||
bindings: {
|
||||
enter: {
|
||||
key: 13,
|
||||
handler: function () {
|
||||
// 覆盖默认的回车键换行
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
theme: 'snow'
|
||||
})
|
||||
this.quill.on('selection-change', range => {
|
||||
this.lastRange = this.range
|
||||
this.range = null
|
||||
if (range) {
|
||||
let bounds = this.quill.getBounds(range.index, range.length)
|
||||
let rect = this.textEditNode.getBoundingClientRect()
|
||||
let rectInfo = {
|
||||
left: bounds.left + rect.left,
|
||||
top: bounds.top + rect.top,
|
||||
right: bounds.right + rect.left,
|
||||
bottom: bounds.bottom + rect.top,
|
||||
width: bounds.width
|
||||
}
|
||||
let formatInfo = this.quill.getFormat(range.index, range.length)
|
||||
let hasRange = false
|
||||
if (range.length == 0) {
|
||||
hasRange = false
|
||||
} else {
|
||||
this.range = range
|
||||
hasRange = true
|
||||
}
|
||||
this.mindMap.emit(
|
||||
'rich_text_selection_change',
|
||||
hasRange,
|
||||
rectInfo,
|
||||
formatInfo
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 选中全部
|
||||
selectAll() {
|
||||
this.quill.setSelection(0, this.quill.getLength())
|
||||
}
|
||||
|
||||
// 格式化当前选中的文本
|
||||
formatText(config = {}, clear = false) {
|
||||
if (!this.range && !this.lastRange) return
|
||||
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)
|
||||
if (rangeLost) {
|
||||
this.quill.setSelection(this.lastRange.index, this.lastRange.length)
|
||||
}
|
||||
}
|
||||
|
||||
// 清除当前选中文本的样式
|
||||
removeFormat() {
|
||||
this.formatText({}, true)
|
||||
}
|
||||
|
||||
// 格式化指定范围的文本
|
||||
formatRangeText(range, config = {}) {
|
||||
if (!range) return
|
||||
this.syncFormatToNodeConfig(config)
|
||||
this.quill.formatText(range.index, range.length, config)
|
||||
}
|
||||
|
||||
// 格式化所有文本
|
||||
formatAllText(config = {}) {
|
||||
this.syncFormatToNodeConfig(config)
|
||||
this.quill.formatText(0, this.quill.getLength(), config)
|
||||
}
|
||||
|
||||
// 同步格式化到节点样式配置
|
||||
syncFormatToNodeConfig(config, clear) {
|
||||
if (!this.node) return
|
||||
if (clear) {
|
||||
// 清除文本样式
|
||||
['fontFamily', 'fontSize', 'fontWeight', 'fontStyle', 'textDecoration', 'color'].forEach((prop) => {
|
||||
delete this.node.nodeData.data[prop]
|
||||
})
|
||||
} else {
|
||||
let data = this.richTextStyleToNormalStyle(config)
|
||||
this.mindMap.renderer.setNodeData(this.node, data)
|
||||
}
|
||||
}
|
||||
|
||||
// 将普通节点样式对象转换成富文本样式对象
|
||||
normalStyleToRichTextStyle(style) {
|
||||
let config = {}
|
||||
Object.keys(style).forEach(prop => {
|
||||
let value = style[prop]
|
||||
switch (prop) {
|
||||
case 'fontFamily':
|
||||
config.font = value
|
||||
break
|
||||
case 'fontSize':
|
||||
config.size = value + 'px'
|
||||
break
|
||||
case 'fontWeight':
|
||||
config.bold = value === 'bold'
|
||||
break
|
||||
case 'fontStyle':
|
||||
config.italic = value === 'italic'
|
||||
break
|
||||
case 'textDecoration':
|
||||
config.underline = value === 'underline'
|
||||
config.strike = value === 'line-through'
|
||||
break
|
||||
case 'color':
|
||||
config.color = value
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
return config
|
||||
}
|
||||
|
||||
// 将富文本样式对象转换成普通节点样式对象
|
||||
richTextStyleToNormalStyle(config) {
|
||||
let data = {}
|
||||
Object.keys(config).forEach(prop => {
|
||||
let value = config[prop]
|
||||
switch (prop) {
|
||||
case 'font':
|
||||
data.fontFamily = value
|
||||
break
|
||||
case 'size':
|
||||
data.fontSize = parseFloat(value)
|
||||
break
|
||||
case 'bold':
|
||||
data.fontWeight = value ? 'bold' : 'normal'
|
||||
break
|
||||
case 'italic':
|
||||
data.fontStyle = value ? 'italic' : 'normal'
|
||||
break
|
||||
case 'underline':
|
||||
data.textDecoration = value ? 'underline' : 'none'
|
||||
break
|
||||
case 'strike':
|
||||
data.textDecoration = value ? 'line-through' : 'none'
|
||||
break
|
||||
case 'color':
|
||||
data.color = value
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
// 将svg中嵌入的dom元素转换成图片
|
||||
async _handleSvgDomElements(svg) {
|
||||
svg = svg.clone()
|
||||
let foreignObjectList = svg.find('foreignObject')
|
||||
let task = foreignObjectList.map(async item => {
|
||||
let clone = item.first().node.cloneNode(true)
|
||||
let div = document.createElement('div')
|
||||
div.style.cssText = `position: fixed; left: -999999px;`
|
||||
div.appendChild(clone)
|
||||
this.mindMap.el.appendChild(div)
|
||||
let canvas = await html2canvas(clone, {
|
||||
backgroundColor: null
|
||||
})
|
||||
this.mindMap.el.removeChild(div)
|
||||
let imgNode = new SvgImage()
|
||||
.load(canvas.toDataURL())
|
||||
.size(canvas.width, canvas.height)
|
||||
item.replace(imgNode)
|
||||
})
|
||||
await Promise.all(task)
|
||||
return {
|
||||
svg: svg,
|
||||
svgHTML: svg.svg()
|
||||
}
|
||||
}
|
||||
|
||||
// 将svg中嵌入的dom元素转换成图片
|
||||
handleSvgDomElements(svg) {
|
||||
return new Promise((resolve, reject) => {
|
||||
svg = svg.clone()
|
||||
let foreignObjectList = svg.find('foreignObject')
|
||||
let index = 0
|
||||
let len = foreignObjectList.length
|
||||
let transform = async () => {
|
||||
this.mindMap.emit('transforming-dom-to-images', index, len)
|
||||
try {
|
||||
let item = foreignObjectList[index++]
|
||||
let parent = item.parent()
|
||||
let clone = item.first().node.cloneNode(true)
|
||||
let div = document.createElement('div')
|
||||
div.style.cssText = `position: fixed; left: -999999px;`
|
||||
div.appendChild(clone)
|
||||
this.mindMap.el.appendChild(div)
|
||||
let canvas = await html2canvas(clone, {
|
||||
backgroundColor: null
|
||||
})
|
||||
// 优先使用原始宽高,因为当设备的window.devicePixelRatio不为1时,html2canvas输出的图片会更大
|
||||
let imgNodeWidth = parent.attr('data-width') || canvas.width
|
||||
let imgNodeHeight = parent.attr('data-height') || canvas.height
|
||||
this.mindMap.el.removeChild(div)
|
||||
let imgNode = new SvgImage()
|
||||
.load(canvas.toDataURL())
|
||||
.size(imgNodeWidth, imgNodeHeight)
|
||||
.x((parent ? parent.attr('data-offsetx') : 0) || 0)
|
||||
item.replace(imgNode)
|
||||
if (index <= len - 1) {
|
||||
setTimeout(() => {
|
||||
transform()
|
||||
}, 0)
|
||||
} else {
|
||||
resolve({
|
||||
svg: svg,
|
||||
svgHTML: svg.svg()
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
}
|
||||
if (len > 0) transform()
|
||||
})
|
||||
}
|
||||
|
||||
// 将所有节点转换成非富文本节点
|
||||
transformAllNodesToNormalNode() {
|
||||
let div = document.createElement('div')
|
||||
walk(
|
||||
this.mindMap.renderer.renderTree,
|
||||
null,
|
||||
node => {
|
||||
if (node.data.richText) {
|
||||
node.data.richText = false
|
||||
div.innerHTML = node.data.text
|
||||
node.data.text = div.textContent
|
||||
}
|
||||
},
|
||||
null,
|
||||
true,
|
||||
0,
|
||||
0
|
||||
)
|
||||
this.mindMap.reRender()
|
||||
}
|
||||
|
||||
// 插件被移除前做的事情
|
||||
beforePluginRemove() {
|
||||
this.transformAllNodesToNormalNode()
|
||||
}
|
||||
}
|
||||
|
||||
RichText.instanceName = 'richText'
|
||||
|
||||
export default RichText
|
||||
@@ -124,12 +124,24 @@ class Style {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取文本样式
|
||||
getTextFontStyle() {
|
||||
return {
|
||||
italic: this.merge('fontStyle') === 'italic',
|
||||
bold: this.merge('fontWeight'),
|
||||
fontSize: this.merge('fontSize'),
|
||||
fontFamily: this.merge('fontFamily')
|
||||
}
|
||||
}
|
||||
|
||||
// html文字节点
|
||||
|
||||
domText(node, fontSizeScale = 1) {
|
||||
node.style.fontFamily = this.merge('fontFamily')
|
||||
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
||||
node.style.lineHeight = this.merge('lineHeight')
|
||||
node.style.fontStyle = this.merge('fontStyle')
|
||||
}
|
||||
|
||||
// 标签文字
|
||||
|
||||
@@ -50,7 +50,12 @@ export default class TextEdit {
|
||||
|
||||
// 显示文本编辑框
|
||||
show(node) {
|
||||
this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect())
|
||||
let rect = node._textData.node.node.getBoundingClientRect()
|
||||
if (this.mindMap.richText) {
|
||||
this.mindMap.richText.showEditText(node, rect)
|
||||
return
|
||||
}
|
||||
this.showEditTextBox(node, rect)
|
||||
}
|
||||
|
||||
// 显示文本编辑框
|
||||
@@ -59,14 +64,17 @@ export default class TextEdit {
|
||||
this.registerTmpShortcut()
|
||||
if (!this.textEditNode) {
|
||||
this.textEditNode = document.createElement('div')
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none;`
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
|
||||
this.textEditNode.setAttribute('contenteditable', true)
|
||||
this.textEditNode.addEventListener('keyup', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
document.body.appendChild(this.textEditNode)
|
||||
}
|
||||
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
||||
let scale = this.mindMap.view.scale
|
||||
let lineHeight = node.style.merge('lineHeight')
|
||||
let fontSize = node.style.merge('fontSize')
|
||||
node.style.domText(this.textEditNode, scale)
|
||||
this.textEditNode.innerHTML = node.nodeData.data.text
|
||||
.split(/\n/gim)
|
||||
.join('<br>')
|
||||
@@ -75,6 +83,8 @@ export default class TextEdit {
|
||||
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 * scale + 'px'
|
||||
this.textEditNode.style.transform = `translateY(${-(lineHeight * fontSize - fontSize) / 2 * scale}px)`
|
||||
this.showTextEdit = true
|
||||
// 选中文本
|
||||
this.selectNodeText()
|
||||
@@ -91,6 +101,9 @@ export default class TextEdit {
|
||||
|
||||
// 隐藏文本编辑框
|
||||
hideEditTextBox() {
|
||||
if (this.mindMap.richText) {
|
||||
return this.mindMap.richText.hideEditText()
|
||||
}
|
||||
if (!this.showTextEdit) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,12 +55,41 @@ class View {
|
||||
})
|
||||
// 放大缩小视图
|
||||
this.mindMap.event.on('mousewheel', (e, dir) => {
|
||||
// // 放大
|
||||
if (dir === 'down') {
|
||||
this.enlarge()
|
||||
if (this.mindMap.opt.customHandleMousewheel && typeof this.mindMap.opt.customHandleMousewheel === 'function') {
|
||||
return this.mindMap.opt.customHandleMousewheel(e)
|
||||
}
|
||||
if (this.mindMap.opt.mousewheelAction === 'zoom') {
|
||||
switch (dir) {
|
||||
// 鼠标滚轮,向上和向左,都是缩小
|
||||
case 'up':
|
||||
case 'left':
|
||||
this.narrow()
|
||||
break
|
||||
// 鼠标滚轮,向下和向右,都是放大
|
||||
case 'down':
|
||||
case 'right':
|
||||
this.enlarge()
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// 缩小
|
||||
this.narrow()
|
||||
switch (dir){
|
||||
// 上移
|
||||
case 'down':
|
||||
this.translateY(-this.mindMap.opt.mousewheelMoveStep)
|
||||
break
|
||||
// 下移
|
||||
case 'up':
|
||||
this.translateY(this.mindMap.opt.mousewheelMoveStep)
|
||||
break
|
||||
// 右移
|
||||
case 'left':
|
||||
this.translateX(-this.mindMap.opt.mousewheelMoveStep)
|
||||
break
|
||||
// 左移
|
||||
case 'right':
|
||||
this.translateX(this.mindMap.opt.mousewheelMoveStep)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,6 +20,11 @@ class Watermark {
|
||||
this.updateWatermark(this.mindMap.opt.watermarkConfig || {})
|
||||
}
|
||||
|
||||
// 获取是否存在水印
|
||||
hasWatermark() {
|
||||
return !!this.text.trim()
|
||||
}
|
||||
|
||||
// 处理水印配置
|
||||
handleConfig({ text, lineSpacing, textSpacing, angle, textStyle }) {
|
||||
this.text = text === undefined ? '' : String(text).trim()
|
||||
@@ -36,7 +41,7 @@ class Watermark {
|
||||
// 非精确绘制,会绘制一些超出可视区域的水印
|
||||
draw() {
|
||||
this.watermarkDraw.clear()
|
||||
if (!this.text.trim()) {
|
||||
if (!this.hasWatermark()) {
|
||||
return
|
||||
}
|
||||
let x = 0
|
||||
|
||||
10
simple-mind-map/src/css/quill.css
Normal file
@@ -0,0 +1,10 @@
|
||||
.ql-editor {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.ql-container {
|
||||
height: auto;
|
||||
font-size: inherit;
|
||||
}
|
||||
@@ -1,267 +1,289 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 逻辑结构图
|
||||
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
btn.translate(
|
||||
width - translateX,
|
||||
height / 2 - translateY + nodeUseLineStyleOffset
|
||||
)
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 逻辑结构图
|
||||
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
btn.translate(
|
||||
width - translateX,
|
||||
height / 2 - translateY + nodeUseLineStyleOffset
|
||||
)
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let y1 = top
|
||||
let x2 = right + generalizationLineMargin
|
||||
let y2 = bottom
|
||||
let cx = x1 + 20
|
||||
let cy = y1 + (y2 - y1) / 2
|
||||
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
gLine.plot(path)
|
||||
gNode.left = right + generalizationNodeMargin
|
||||
gNode.top = top + (bottom - top - gNode.height) / 2
|
||||
}
|
||||
}
|
||||
|
||||
export default LogicalStructure
|
||||
|
||||
@@ -208,11 +208,12 @@ class MindMap extends Base {
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 = 0
|
||||
let _s = 0
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
if (item.dir === 'left') {
|
||||
@@ -226,6 +227,8 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
@@ -241,6 +244,7 @@ class MindMap extends Base {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0
|
||||
@@ -251,9 +255,11 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
if (nodeUseLineStyle) {
|
||||
if (item.dir === 'left') {
|
||||
nodeUseLineStylePath = ` L ${item.left},${y2}`
|
||||
} else {
|
||||
@@ -273,6 +279,7 @@ class MindMap extends Base {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0
|
||||
@@ -284,6 +291,8 @@ class MindMap extends Base {
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
|
||||
@@ -26,6 +26,14 @@ export default {
|
||||
generalizationLineMargin: 0,
|
||||
// 概要节点距节点的距离
|
||||
generalizationNodeMargin: 20,
|
||||
// 关联线默认状态的粗细
|
||||
associativeLineWidth: 2,
|
||||
// 关联线默认状态的颜色
|
||||
associativeLineColor: 'rgb(51, 51, 51)',
|
||||
// 关联线激活状态的粗细
|
||||
associativeLineActiveWidth: 8,
|
||||
// 关联线激活状态的颜色
|
||||
associativeLineActiveColor: 'rgba(2, 167, 240, 1)',
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
|
||||
@@ -136,6 +136,8 @@ export const copyRenderTree = (tree, root) => {
|
||||
// 复制节点树数据
|
||||
export const copyNodeTree = (tree, root, removeActiveState = false) => {
|
||||
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
|
||||
// 去除节点id,因为节点id不能重复
|
||||
if (tree.data.id) delete tree.data.id
|
||||
if (removeActiveState) {
|
||||
tree.data.isActive = false
|
||||
}
|
||||
@@ -193,12 +195,12 @@ export const downloadFile = (file, fileName) => {
|
||||
// 节流函数
|
||||
export const throttle = (fn, time = 300, ctx) => {
|
||||
let timer = null
|
||||
return () => {
|
||||
return (...args) => {
|
||||
if (timer) {
|
||||
return
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
fn.call(ctx)
|
||||
fn.call(ctx, ...args)
|
||||
timer = null
|
||||
}, time)
|
||||
}
|
||||
@@ -235,4 +237,34 @@ export const camelCaseToHyphen = (str) => {
|
||||
return str.replace(/([a-z])([A-Z])/g, (...args) => {
|
||||
return args[1] + '-' + args[2].toLowerCase()
|
||||
})
|
||||
}
|
||||
|
||||
//计算节点的文本长宽
|
||||
let measureTextContext = null
|
||||
export const measureText = (text, { italic, bold, fontSize, fontFamily }) => {
|
||||
const font = joinFontStr({
|
||||
italic,
|
||||
bold,
|
||||
fontSize,
|
||||
fontFamily
|
||||
})
|
||||
if (!measureTextContext) {
|
||||
const canvas = document.createElement('canvas')
|
||||
measureTextContext = canvas.getContext('2d')
|
||||
}
|
||||
measureTextContext.save()
|
||||
measureTextContext.font = font
|
||||
const {
|
||||
width,
|
||||
actualBoundingBoxAscent,
|
||||
actualBoundingBoxDescent
|
||||
} = measureTextContext.measureText(text)
|
||||
measureTextContext.restore()
|
||||
const height = actualBoundingBoxAscent + actualBoundingBoxDescent
|
||||
return { width, height }
|
||||
}
|
||||
|
||||
// 拼接font字符串
|
||||
export const joinFontStr = ({ italic, bold, fontSize, fontFamily }) => {
|
||||
return `${italic ? 'italic ' : ''} ${bold ? 'bold ' : ''} ${fontSize}px ${fontFamily} `
|
||||
}
|
||||
2
web/package-lock.json
generated
@@ -17906,6 +17906,7 @@
|
||||
"integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/core": "^7.11.0",
|
||||
"@babel/helper-compilation-targets": "^7.9.6",
|
||||
"@babel/helper-module-imports": "^7.8.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
@@ -17918,6 +17919,7 @@
|
||||
"@vue/babel-plugin-jsx": "^1.0.3",
|
||||
"@vue/babel-preset-jsx": "^1.2.4",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"core-js": "^3.6.5",
|
||||
"core-js-compat": "^3.6.5",
|
||||
"semver": "^6.1.0"
|
||||
}
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1673600274529') format('woff2'),
|
||||
url('iconfont.woff?t=1673600274529') format('woff'),
|
||||
url('iconfont.ttf?t=1673600274529') format('truetype');
|
||||
src: url('iconfont.woff2?t=1678955183884') format('woff2'),
|
||||
url('iconfont.woff?t=1678955183884') format('woff'),
|
||||
url('iconfont.ttf?t=1678955183884') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,90 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconlianjiexian:before {
|
||||
content: "\e75b";
|
||||
}
|
||||
|
||||
.iconbangzhu:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.iconshezhi:before {
|
||||
content: "\e8b7";
|
||||
}
|
||||
|
||||
.iconwushuju:before {
|
||||
content: "\e643";
|
||||
}
|
||||
|
||||
.iconzuijinliulan:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon3zuidahua-3:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.iconzuixiaohua:before {
|
||||
content: "\e650";
|
||||
}
|
||||
|
||||
.iconzuidahua:before {
|
||||
content: "\e651";
|
||||
}
|
||||
|
||||
.iconguanbi:before {
|
||||
content: "\e652";
|
||||
}
|
||||
|
||||
.icondiannao:before {
|
||||
content: "\eac0";
|
||||
}
|
||||
|
||||
.iconzhuye:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.iconbendi1x:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.iconbeijingyanse:before {
|
||||
content: "\e6f8";
|
||||
}
|
||||
|
||||
.iconqingchu:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.iconcase:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.iconxingzhuang-wenzi:before {
|
||||
content: "\eb99";
|
||||
}
|
||||
|
||||
.iconzitijiacu:before {
|
||||
content: "\ec83";
|
||||
}
|
||||
|
||||
.iconzitixiahuaxian:before {
|
||||
content: "\ec85";
|
||||
}
|
||||
|
||||
.iconzitixieti:before {
|
||||
content: "\ec86";
|
||||
}
|
||||
|
||||
.iconshanchuxian:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.iconzitiyanse:before {
|
||||
content: "\e854";
|
||||
}
|
||||
|
||||
.icongithub:before {
|
||||
content: "\e64f";
|
||||
}
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
{
|
||||
"id": "2479351",
|
||||
"name": "思绪",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon",
|
||||
"description": "思维导图",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "8760187",
|
||||
"name": "github",
|
||||
"font_class": "github",
|
||||
"unicode": "e64f",
|
||||
"unicode_decimal": 58959
|
||||
},
|
||||
{
|
||||
"icon_id": "1009019",
|
||||
"name": "选择",
|
||||
"font_class": "choose1",
|
||||
"unicode": "e6c5",
|
||||
"unicode_decimal": 59077
|
||||
},
|
||||
{
|
||||
"icon_id": "493507",
|
||||
"name": "主题",
|
||||
"font_class": "zhuti",
|
||||
"unicode": "e7aa",
|
||||
"unicode_decimal": 59306
|
||||
},
|
||||
{
|
||||
"icon_id": "1305460",
|
||||
"name": "导出",
|
||||
"font_class": "daochu1",
|
||||
"unicode": "e63e",
|
||||
"unicode_decimal": 58942
|
||||
},
|
||||
{
|
||||
"icon_id": "4784101",
|
||||
"name": "另存为",
|
||||
"font_class": "lingcunwei",
|
||||
"unicode": "e657",
|
||||
"unicode_decimal": 58967
|
||||
},
|
||||
{
|
||||
"icon_id": "9929033",
|
||||
"name": "export",
|
||||
"font_class": "export",
|
||||
"unicode": "e642",
|
||||
"unicode_decimal": 58946
|
||||
},
|
||||
{
|
||||
"icon_id": "4570294",
|
||||
"name": "打开",
|
||||
"font_class": "dakai",
|
||||
"unicode": "ebdf",
|
||||
"unicode_decimal": 60383
|
||||
},
|
||||
{
|
||||
"icon_id": "5086088",
|
||||
"name": "新建",
|
||||
"font_class": "xinjian",
|
||||
"unicode": "e64e",
|
||||
"unicode_decimal": 58958
|
||||
},
|
||||
{
|
||||
"icon_id": "1117",
|
||||
"name": "剪切",
|
||||
"font_class": "jianqie",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "1415523",
|
||||
"name": "整理",
|
||||
"font_class": "zhengli",
|
||||
"unicode": "e83b",
|
||||
"unicode_decimal": 59451
|
||||
},
|
||||
{
|
||||
"icon_id": "2815710",
|
||||
"name": "复制",
|
||||
"font_class": "fuzhi",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "11121506",
|
||||
"name": "粘贴",
|
||||
"font_class": "niantie",
|
||||
"unicode": "e63f",
|
||||
"unicode_decimal": 58943
|
||||
},
|
||||
{
|
||||
"icon_id": "11383392",
|
||||
"name": "上移",
|
||||
"font_class": "shangyi",
|
||||
"unicode": "e6be",
|
||||
"unicode_decimal": 59070
|
||||
},
|
||||
{
|
||||
"icon_id": "11383396",
|
||||
"name": "下移",
|
||||
"font_class": "xiayi",
|
||||
"unicode": "e6bf",
|
||||
"unicode_decimal": 59071
|
||||
},
|
||||
{
|
||||
"icon_id": "14843439",
|
||||
"name": "概括总览",
|
||||
"font_class": "gaikuozonglan",
|
||||
"unicode": "e609",
|
||||
"unicode_decimal": 58889
|
||||
},
|
||||
{
|
||||
"icon_id": "19738998",
|
||||
"name": "全选",
|
||||
"font_class": "quanxuan",
|
||||
"unicode": "f199",
|
||||
"unicode_decimal": 61849
|
||||
},
|
||||
{
|
||||
"icon_id": "17606306",
|
||||
"name": "导入",
|
||||
"font_class": "daoru",
|
||||
"unicode": "e6a3",
|
||||
"unicode_decimal": 59043
|
||||
},
|
||||
{
|
||||
"icon_id": "5110748",
|
||||
"name": "后退-实",
|
||||
"font_class": "houtui-shi",
|
||||
"unicode": "e656",
|
||||
"unicode_decimal": 58966
|
||||
},
|
||||
{
|
||||
"icon_id": "14420971",
|
||||
"name": "前进",
|
||||
"font_class": "qianjin1",
|
||||
"unicode": "e654",
|
||||
"unicode_decimal": 58964
|
||||
},
|
||||
{
|
||||
"icon_id": "1368553",
|
||||
"name": "撤回",
|
||||
"font_class": "withdraw",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
},
|
||||
{
|
||||
"icon_id": "15006636",
|
||||
"name": "前进",
|
||||
"font_class": "qianjin",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "19980541",
|
||||
"name": "恢复默认",
|
||||
"font_class": "huifumoren",
|
||||
"unicode": "e60e",
|
||||
"unicode_decimal": 58894
|
||||
},
|
||||
{
|
||||
"icon_id": "1616783",
|
||||
"name": "换行",
|
||||
"font_class": "huanhang",
|
||||
"unicode": "e61e",
|
||||
"unicode_decimal": 58910
|
||||
},
|
||||
{
|
||||
"icon_id": "4777227",
|
||||
"name": "缩小",
|
||||
"font_class": "suoxiao",
|
||||
"unicode": "ec13",
|
||||
"unicode_decimal": 60435
|
||||
},
|
||||
{
|
||||
"icon_id": "18811980",
|
||||
"name": "编辑",
|
||||
"font_class": "bianji",
|
||||
"unicode": "e626",
|
||||
"unicode_decimal": 58918
|
||||
},
|
||||
{
|
||||
"icon_id": "21188137",
|
||||
"name": "放大",
|
||||
"font_class": "fangda",
|
||||
"unicode": "e663",
|
||||
"unicode_decimal": 58979
|
||||
},
|
||||
{
|
||||
"icon_id": "21189639",
|
||||
"name": "全屏",
|
||||
"font_class": "quanping1",
|
||||
"unicode": "e664",
|
||||
"unicode_decimal": 58980
|
||||
},
|
||||
{
|
||||
"icon_id": "397753",
|
||||
"name": "定位",
|
||||
"font_class": "dingwei",
|
||||
"unicode": "e616",
|
||||
"unicode_decimal": 58902
|
||||
},
|
||||
{
|
||||
"icon_id": "2605158",
|
||||
"name": "导航",
|
||||
"font_class": "daohang",
|
||||
"unicode": "e611",
|
||||
"unicode_decimal": 58897
|
||||
},
|
||||
{
|
||||
"icon_id": "6528451",
|
||||
"name": "键盘",
|
||||
"font_class": "jianpan",
|
||||
"unicode": "e64d",
|
||||
"unicode_decimal": 58957
|
||||
},
|
||||
{
|
||||
"icon_id": "7556170",
|
||||
"name": "全屏",
|
||||
"font_class": "quanping",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "788015",
|
||||
"name": "导出",
|
||||
"font_class": "daochu",
|
||||
"unicode": "e63d",
|
||||
"unicode_decimal": 58941
|
||||
},
|
||||
{
|
||||
"icon_id": "2678575",
|
||||
"name": "标签",
|
||||
"font_class": "biaoqian",
|
||||
"unicode": "e63c",
|
||||
"unicode_decimal": 58940
|
||||
},
|
||||
{
|
||||
"icon_id": "6265396",
|
||||
"name": "流程-备注",
|
||||
"font_class": "flow-Mark",
|
||||
"unicode": "e65b",
|
||||
"unicode_decimal": 58971
|
||||
},
|
||||
{
|
||||
"icon_id": "1790486",
|
||||
"name": "超链接",
|
||||
"font_class": "chaolianjie",
|
||||
"unicode": "e6f4",
|
||||
"unicode_decimal": 59124
|
||||
},
|
||||
{
|
||||
"icon_id": "4608986",
|
||||
"name": "主题",
|
||||
"font_class": "jingzi",
|
||||
"unicode": "e610",
|
||||
"unicode_decimal": 58896
|
||||
},
|
||||
{
|
||||
"icon_id": "11903017",
|
||||
"name": "笑脸",
|
||||
"font_class": "xiaolian",
|
||||
"unicode": "e60f",
|
||||
"unicode_decimal": 58895
|
||||
},
|
||||
{
|
||||
"icon_id": "19657962",
|
||||
"name": "图 片",
|
||||
"font_class": "image",
|
||||
"unicode": "e629",
|
||||
"unicode_decimal": 58921
|
||||
},
|
||||
{
|
||||
"icon_id": "20784489",
|
||||
"name": "结构",
|
||||
"font_class": "jiegou",
|
||||
"unicode": "e61d",
|
||||
"unicode_decimal": 58909
|
||||
},
|
||||
{
|
||||
"icon_id": "15969341",
|
||||
"name": "样式",
|
||||
"font_class": "yangshi",
|
||||
"unicode": "e631",
|
||||
"unicode_decimal": 58929
|
||||
},
|
||||
{
|
||||
"icon_id": "2967176",
|
||||
"name": "符号-大纲树",
|
||||
"font_class": "fuhao-dagangshu",
|
||||
"unicode": "e71f",
|
||||
"unicode_decimal": 59167
|
||||
},
|
||||
{
|
||||
"icon_id": "12316668",
|
||||
"name": "添加子节点",
|
||||
"font_class": "tianjiazijiedian",
|
||||
"unicode": "e622",
|
||||
"unicode_decimal": 58914
|
||||
},
|
||||
{
|
||||
"icon_id": "14435368",
|
||||
"name": "节点",
|
||||
"font_class": "jiedian",
|
||||
"unicode": "e655",
|
||||
"unicode_decimal": 58965
|
||||
},
|
||||
{
|
||||
"icon_id": "15765352",
|
||||
"name": "删 除",
|
||||
"font_class": "shanchu",
|
||||
"unicode": "e696",
|
||||
"unicode_decimal": 59030
|
||||
},
|
||||
{
|
||||
"icon_id": "9592600",
|
||||
"name": "HTSCIT_展开",
|
||||
"font_class": "zhankai",
|
||||
"unicode": "e64c",
|
||||
"unicode_decimal": 58956
|
||||
},
|
||||
{
|
||||
"icon_id": "9900009",
|
||||
"name": "HTSCIT_展开2",
|
||||
"font_class": "zhankai1",
|
||||
"unicode": "e673",
|
||||
"unicode_decimal": 58995
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -34,7 +34,16 @@ export default {
|
||||
watermarkTextSpacing: 'Text spacing',
|
||||
watermarkAngle: 'Angle',
|
||||
watermarkTextOpacity: 'Text opacity',
|
||||
watermarkTextFontSize: 'Font size'
|
||||
watermarkTextFontSize: 'Font size',
|
||||
isEnableNodeRichText: 'Enable node rich text editing',
|
||||
mousewheelAction: 'Mouse wheel behavior',
|
||||
zoomView: 'Zoom view',
|
||||
moveViewUpDown: 'Move view up and down',
|
||||
associativeLine: 'Associative line',
|
||||
associativeLineWidth: 'Width',
|
||||
associativeLineColor: 'Color',
|
||||
associativeLineActiveWidth: 'Active width',
|
||||
associativeLineActiveColor: 'Active color'
|
||||
},
|
||||
color: {
|
||||
moreColor: 'More color'
|
||||
@@ -79,7 +88,13 @@ export default {
|
||||
imageFile: 'Image file',
|
||||
svgFile: 'svg file',
|
||||
pdfFile: 'pdf file',
|
||||
tips: 'tips:.smm and .json file can be import'
|
||||
tips: 'tips: .smm and .json file can be import',
|
||||
domToImage: 'Whether to convert rich text nodes in svg into pictures',
|
||||
pngTips: 'tips: Exporting pictures in rich text mode is time-consuming. It is recommended to export to svg format',
|
||||
svgTips: 'tips: Exporting pictures in rich text mode is time-consuming',
|
||||
transformingDomToImages: 'Converting nodes: ',
|
||||
notifyTitle: 'Info',
|
||||
notifyMessage: 'If the download is not triggered, check whether it is blocked by the browser'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: 'Full screen show',
|
||||
@@ -177,6 +192,11 @@ export default {
|
||||
saveAs: 'Save as',
|
||||
import: 'Import',
|
||||
export: 'Export',
|
||||
shortcutKey: 'Shortcut key'
|
||||
shortcutKey: 'Shortcut key',
|
||||
associativeLine: 'Associative line',
|
||||
},
|
||||
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.'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,16 @@ export default {
|
||||
watermarkTextSpacing: '水印文字间距',
|
||||
watermarkAngle: '旋转角度',
|
||||
watermarkTextOpacity: '文字透明度',
|
||||
watermarkTextFontSize: '文字字号'
|
||||
watermarkTextFontSize: '文字字号',
|
||||
isEnableNodeRichText: '是否开启节点富文本编辑',
|
||||
mousewheelAction: '鼠标滚轮行为',
|
||||
zoomView: '缩放视图',
|
||||
moveViewUpDown: '上下移动视图',
|
||||
associativeLine: '关联线',
|
||||
associativeLineWidth: '粗细',
|
||||
associativeLineColor: '颜色',
|
||||
associativeLineActiveWidth: '激活粗细',
|
||||
associativeLineActiveColor: '激活颜色'
|
||||
},
|
||||
color: {
|
||||
moreColor: '更多颜色'
|
||||
@@ -79,7 +88,13 @@ export default {
|
||||
imageFile: '图片文件',
|
||||
svgFile: 'svg文件',
|
||||
pdfFile: 'pdf文件',
|
||||
tips: 'tips:.smm和.json文件可用于导入'
|
||||
tips: 'tips:.smm和.json文件可用于导入',
|
||||
domToImage: '是否将svg中富文本节点转换成图片',
|
||||
pngTips: 'tips:富文本模式导出图片非常耗时,建议导出为svg格式',
|
||||
svgTips: 'tips:富文本模式导出图片非常耗时',
|
||||
transformingDomToImages: '正在转换节点:',
|
||||
notifyTitle: '消息',
|
||||
notifyMessage: '如果没有触发下载,请检查是否被浏览器拦截了'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: '全屏查看',
|
||||
@@ -177,6 +192,11 @@ export default {
|
||||
saveAs: '另存为',
|
||||
import: '导入',
|
||||
export: '导出',
|
||||
shortcutKey: '快捷键'
|
||||
shortcutKey: '快捷键',
|
||||
associativeLine: '关联线',
|
||||
},
|
||||
edit: {
|
||||
newFeatureNoticeTitle: '新特性提醒',
|
||||
newFeatureNoticeMessage: '本次更新支持了节点富文本编辑,但是存在一定缺陷,最主要的影响是导出为图片的时间和节点数量成正比,所以对导出需求比较依赖的话可以通过【基础样式】-【其他配置】-【是否开启节点富文本编辑】设置关掉富文本编辑模式。'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ let APIList = [
|
||||
'keyCommand',
|
||||
'command',
|
||||
'batchExecution',
|
||||
'richText',
|
||||
'select',
|
||||
'drag',
|
||||
'keyboardNavigation',
|
||||
'doExport',
|
||||
'miniMap',
|
||||
'watermark',
|
||||
'associativeLine',
|
||||
'xmind',
|
||||
'utils'
|
||||
]
|
||||
|
||||
@@ -52,7 +52,6 @@ export default {
|
||||
this.onScroll()
|
||||
},
|
||||
lang(newVal, oldVal) {
|
||||
console.log(newVal, oldVal)
|
||||
if (!oldVal) {
|
||||
return
|
||||
}
|
||||
|
||||
87
web/src/pages/Doc/en/associativeLine/index.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# AssociativeLine plugin
|
||||
|
||||
> v0.4.5+
|
||||
|
||||
This plugin is used to support the addition of associative lines.
|
||||
|
||||
The plugin currently has relatively simple functions, and does not support modifying the control points of association lines or adding text to association lines.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js'
|
||||
|
||||
MindMap.usePlugin(AssociativeLine)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.associativeLine`.
|
||||
|
||||
## Config
|
||||
|
||||
Support for modifying the thickness and color of associated lines, divided into default and active states. The configuration is as follows:
|
||||
|
||||
- `associativeLineWidth`: The thickness of the default state of the associated line. The default value is `2`
|
||||
|
||||
- `associativeLineColor`: Color of the default state of associative lines. The default value is `rgb(51, 51, 51)`
|
||||
|
||||
- `associativeLineActiveWidth`: The thickness of the active state of the associated line. The default value is `8`
|
||||
|
||||
- `associativeLineActiveColor`: The color of the active state of the associated line. The default value is `rgba(2, 167, 240, 1)`
|
||||
|
||||
The configuration is provided as a theme, so if you want to modify these four properties, you can modify them using the `mindMap.setThemeConfig(config)` method.
|
||||
|
||||
## Props
|
||||
|
||||
### mindMap.associativeLine.lineList
|
||||
|
||||
Currently, all connection line data, array types, and each item of the array are also an array:
|
||||
|
||||
```js
|
||||
[
|
||||
path, // Connector node
|
||||
clickPath, // Invisible click line node
|
||||
node, // Start node
|
||||
toNode // Target node
|
||||
]
|
||||
```
|
||||
|
||||
### mindMap.associativeLine.activeLine
|
||||
|
||||
The currently active connection line and array type are the same as the structure of each item in the `lineList` array.
|
||||
|
||||
## Methods
|
||||
|
||||
### renderAllLines()
|
||||
|
||||
Re-render all associated lines.
|
||||
|
||||
### removeAllLines()
|
||||
|
||||
Remove all associated lines.
|
||||
|
||||
### createLineFromActiveNode()
|
||||
|
||||
Create an associated line from the current active node. If there are multiple active nodes, the default is the first node.
|
||||
|
||||
After calling this method, an association line will be rendered from the first active node to the current mouse real-time position. When a target node is clicked, it represents completion of creation. An association line will be rendered between the first active node and the clicked node.
|
||||
|
||||
### createLine(fromNode)
|
||||
|
||||
Creates an associative line starting at the specified node.
|
||||
|
||||
After calling this method, an association line will be rendered from the specified node to the current mouse real-time position. When a target node is clicked, it represents completion of creation, and an association line will be rendered between the specified node and the clicked node.
|
||||
|
||||
### addLine(fromNode, toNode)
|
||||
|
||||
Add an associative line directly.
|
||||
|
||||
Calling this method will directly create an association line from the `fromNode` to the `toNode` node.
|
||||
|
||||
### removeLine()
|
||||
|
||||
Deletes the currently active associative line. Clicking on an associated line is considered active.
|
||||
|
||||
### clearActiveLine()
|
||||
|
||||
Clears the active state of the currently active association line.
|
||||
75
web/src/pages/Doc/en/associativeLine/index.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>AssociativeLine plugin</h1>
|
||||
<blockquote>
|
||||
<p>v0.4.5+</p>
|
||||
</blockquote>
|
||||
<p>This plugin is used to support the addition of associative lines.</p>
|
||||
<p>The plugin currently has relatively simple functions, and does not support modifying the control points of association lines or adding text to association 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">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/AssociativeLine.js'</span>
|
||||
|
||||
MindMap.usePlugin(AssociativeLine)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.associativeLine</code>.</p>
|
||||
<h2>Config</h2>
|
||||
<p>Support for modifying the thickness and color of associated lines, divided into default and active states. The configuration is as follows:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>associativeLineWidth</code>: The thickness of the default state of the associated line. The default value is <code>2</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineColor</code>: Color of the default state of associative lines. The default value is <code>rgb(51, 51, 51)</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineActiveWidth</code>: The thickness of the active state of the associated line. The default value is <code>8</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineActiveColor</code>: The color of the active state of the associated line. The default value is <code>rgba(2, 167, 240, 1)</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The configuration is provided as a theme, so if you want to modify these four properties, you can modify them using the <code>mindMap.setThemeConfig(config)</code> method.</p>
|
||||
<h2>Props</h2>
|
||||
<h3>mindMap.associativeLine.lineList</h3>
|
||||
<p>Currently, all connection line data, array types, and each item of the array are also an array:</p>
|
||||
<pre class="hljs"><code>[
|
||||
path, <span class="hljs-comment">// Connector node</span>
|
||||
clickPath, <span class="hljs-comment">// Invisible click line node</span>
|
||||
node, <span class="hljs-comment">// Start node</span>
|
||||
toNode <span class="hljs-comment">// Target node</span>
|
||||
]
|
||||
</code></pre>
|
||||
<h3>mindMap.associativeLine.activeLine</h3>
|
||||
<p>The currently active connection line and array type are the same as the structure of each item in the <code>lineList</code> array.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>renderAllLines()</h3>
|
||||
<p>Re-render all associated lines.</p>
|
||||
<h3>removeAllLines()</h3>
|
||||
<p>Remove all associated lines.</p>
|
||||
<h3>createLineFromActiveNode()</h3>
|
||||
<p>Create an associated line from the current active node. If there are multiple active nodes, the default is the first node.</p>
|
||||
<p>After calling this method, an association line will be rendered from the first active node to the current mouse real-time position. When a target node is clicked, it represents completion of creation. An association line will be rendered between the first active node and the clicked node.</p>
|
||||
<h3>createLine(fromNode)</h3>
|
||||
<p>Creates an associative line starting at the specified node.</p>
|
||||
<p>After calling this method, an association line will be rendered from the specified node to the current mouse real-time position. When a target node is clicked, it represents completion of creation, and an association line will be rendered between the specified node and the clicked node.</p>
|
||||
<h3>addLine(fromNode, toNode)</h3>
|
||||
<p>Add an associative line directly.</p>
|
||||
<p>Calling this method will directly create an association line from the <code>fromNode</code> to the <code>toNode</code> node.</p>
|
||||
<h3>removeLine()</h3>
|
||||
<p>Deletes the currently active associative line. Clicking on an associated line is considered active.</p>
|
||||
<h3>clearActiveLine()</h3>
|
||||
<p>Clears the active state of the currently active association line.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## 0.4.5
|
||||
|
||||
New: 1.Supports associative lines. 2.You can also drag the canvas by holding down the root node. 3. Hold down the ctrl key to adjust multiple selected nodes.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
New: Support horizontal scrolling in response to the mouse.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
Fix: No trigger after forward and backward `data_ Change` event.
|
||||
|
||||
New: Support user-defined mouse wheel events; The mouse wheel is adjusted to support zooming and moving the view up and down.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
New: The `setText` method of the Node class adds a second parameter to support setting rich text content.
|
||||
|
||||
## 0.4.1
|
||||
|
||||
New: 1.Add and throw node mouseenter and mouseleave events; 2.Node rich text supports setting background color; 3.Node rich text supports clear style.
|
||||
|
||||
Fix: 1.Mac system touchpad scaling is the opposite problem; 2.When the device window.devicePixelRatio is not 1, the size of the rich text node in the exported image will become larger when there are rich text nodes.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
New: The node supports rich text editing.
|
||||
|
||||
## 0.3.4
|
||||
|
||||
New: Automatic line wrapping function is added to node text.
|
||||
|
||||
Fix: 1.Fix the problem of deletion exceptions if there are root nodes in the batch deleted nodes. 2.Fix the problem that high node height will overlap with other nodes in the case of bottom edge style.
|
||||
|
||||
## 0.3.3
|
||||
|
||||
Fix: The root node text cannot wrap.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
Fix: 1.Fix the problem that the node style is not updated when the secondary node is dragged to other nodes or other nodes are dragged to the secondary node; 2.Fix the problem that when the actual content of the mind map is larger than the screen width and height, the excess part is not watermarked when exporting.
|
||||
|
||||
## 0.3.1
|
||||
|
||||
Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.4.5</h2>
|
||||
<p>New: 1.Supports associative lines. 2.You can also drag the canvas by holding down the root node. 3. Hold down the ctrl key to adjust multiple selected nodes.</p>
|
||||
<h2>0.4.4</h2>
|
||||
<p>New: Support horizontal scrolling in response to the mouse.</p>
|
||||
<h2>0.4.3</h2>
|
||||
<p>Fix: No trigger after forward and backward <code>data_ Change</code> event.</p>
|
||||
<p>New: Support user-defined mouse wheel events; The mouse wheel is adjusted to support zooming and moving the view up and down.</p>
|
||||
<h2>0.4.2</h2>
|
||||
<p>New: The <code>setText</code> method of the Node class adds a second parameter to support setting rich text content.</p>
|
||||
<h2>0.4.1</h2>
|
||||
<p>New: 1.Add and throw node mouseenter and mouseleave events; 2.Node rich text supports setting background color; 3.Node rich text supports clear style.</p>
|
||||
<p>Fix: 1.Mac system touchpad scaling is the opposite problem; 2.When the device window.devicePixelRatio is not 1, the size of the rich text node in the exported image will become larger when there are rich text nodes.</p>
|
||||
<h2>0.4.0</h2>
|
||||
<p>New: The node supports rich text editing.</p>
|
||||
<h2>0.3.4</h2>
|
||||
<p>New: Automatic line wrapping function is added to node text.</p>
|
||||
<p>Fix: 1.Fix the problem of deletion exceptions if there are root nodes in the batch deleted nodes. 2.Fix the problem that high node height will overlap with other nodes in the case of bottom edge style.</p>
|
||||
<h2>0.3.3</h2>
|
||||
<p>Fix: The root node text cannot wrap.</p>
|
||||
<h2>0.3.2</h2>
|
||||
<p>Fix: 1.Fix the problem that the node style is not updated when the secondary node is dragged to other nodes or other nodes are dragged to the secondary node; 2.Fix the problem that when the actual content of the mind map is larger than the screen width and height, the excess part is not watermarked when exporting.</p>
|
||||
<h2>0.3.1</h2>
|
||||
<p>Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.</p>
|
||||
<p>New: Add position and size settings for background image display. This setting is also supported for exported pictures.</p>
|
||||
|
||||
@@ -40,6 +40,10 @@ const mindMap = new MindMap({
|
||||
| readonly(v0.1.7+) | Boolean | false | Whether it is read-only mode | |
|
||||
| enableFreeDrag(v0.2.4+) | Boolean | false | Enable node free drag | |
|
||||
| watermarkConfig(v0.2.4+) | Object | | Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration | |
|
||||
| textAutoWrapWidth(v0.3.4+) | Number | 500 | Each line of text in the node will wrap automatically when it reaches the width | |
|
||||
| customHandleMousewheel(v0.4.3+) | Function | null | User-defined mouse wheel event processing can pass a function, and the callback parameter is the event object | |
|
||||
| mousewheelAction(v0.4.3+) | String | zoom | The behavior of the mouse wheel, `zoom`(Zoom in and out)、`move`(Move up and down). If `customHandleMousewheel` passes a custom function, this property will not take effect | |
|
||||
| mousewheelMoveStep(v0.4.3+) | Number | 100 | When the `mousewheelAction` is set to `move`, you can use this attribute to control the step length of the view movement when the mouse scrolls. The unit is `px` | |
|
||||
|
||||
### Watermark config
|
||||
|
||||
@@ -81,14 +85,23 @@ mindMap.setTheme('Theme name')
|
||||
|
||||
For all configurations of theme, please refer to [Default Topic](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js). The `defineTheme`method will merge the configuration you passed in with the default configuration. Most of the themes do not need custom many parts. For a typical customized theme configuration, please refer to [blueSky](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js).
|
||||
|
||||
### usePlugin(plugin)
|
||||
### usePlugin(plugin, opt = {})
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
- `opt`:v0.4.0+,Plugin options. If a plugin supports custom options, it can be passed in through this parameter.
|
||||
|
||||
If you need to use some non-core functions, such as mini map, watermark, etc, you can register plugin through this method. Can be called in chain.
|
||||
|
||||
Note: The plugin needs to be registered before instantiating `MindMap`.
|
||||
|
||||
### hasPlugin(plugin)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
Get whether a plugin is registered, The index of the plugin in the registered plugin list is returned, If it is `-1`, it means that the plugin is not registered.
|
||||
|
||||
|
||||
## Static props
|
||||
|
||||
### pluginList
|
||||
@@ -119,12 +132,16 @@ Get the `svg` data and return an object. The detailed structure is as follows:
|
||||
}
|
||||
```
|
||||
|
||||
### render()
|
||||
### render(callback)
|
||||
|
||||
- `callback`: `v0.3.2+`, `Function`, Called when the re-rendering is complete
|
||||
|
||||
Triggers a full rendering, which will reuse nodes for better performance. If
|
||||
only the node positions have changed, this method can be called to `reRender`.
|
||||
|
||||
### reRender()
|
||||
### reRender(callback)
|
||||
|
||||
- `callback`: `v0.3.2+`, `Function`, Called when the re-rendering is complete
|
||||
|
||||
Performs a full re-render, clearing the canvas and creating new nodes. This has
|
||||
poor performance and should be used sparingly.
|
||||
@@ -164,6 +181,8 @@ Listen to an event. Event list:
|
||||
| node_mouseup | Node mouseup event | this (node instance), e (event object) |
|
||||
| node_dblclick | Node double-click event | this (node instance), e (event object) |
|
||||
| node_contextmenu | Node right-click menu event | e (event object), this (node instance) |
|
||||
| node_mouseenter(v0.4.1+) | Node mouseenter event | this (node instance), e (event object) |
|
||||
| node_mouseleave(v0.4.1+) | Node mouseleave event | this (node instance), e (event object) |
|
||||
| before_node_active | Event before node activation | this (node instance), activeNodeList (current list of active nodes) |
|
||||
| node_active | Node activation event | this (node instance), activeNodeList (current list of active nodes) |
|
||||
| expand_btn_click | Node expand or collapse event | this (node instance) |
|
||||
@@ -172,6 +191,11 @@ Listen to an event. Event list:
|
||||
| scale | Zoom event | scale (zoom ratio) |
|
||||
| node_img_dblclick(v0.2.15+) | Node image double-click event | this (node instance), e (event object) |
|
||||
| node_tree_render_end(v0.2.16+) | Node tree render end event | |
|
||||
| rich_text_selection_change(v0.4.0+) | Available when the `RichText` plugin is registered. Triggered when the text selection area changes when the node is edited | hasRange(Whether there is a selection)、rectInfo(Size and location information of the selected area)、formatInfo(Text formatting information of the selected area) |
|
||||
| transforming-dom-to-images(v0.4.0+) | Available when the `RichText` plugin is registered. When there is a `DOM` node in `svg`, the `DOM` node will be converted to an image when exporting to an image. This event will be triggered during the conversion process. You can use this event to prompt the user about the node to which you are currently converting | index(Index of the node currently converted to)、len(Total number of nodes to be converted) |
|
||||
| node_dragging(v0.4.5+) | Triggered when a node is dragged | node(The currently dragged node) |
|
||||
| node_dragend(v0.4.5+) | Triggered when the node is dragged and ends | |
|
||||
| associative_line_click(v0.4.5+) | Triggered when an associated line is clicked | path(Connector node)、clickPath(Invisible click line node)、node(Start node)、toNode(Target node) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
@@ -240,39 +264,39 @@ in the options table above.
|
||||
Executes a command, which will add a record to the history stack for undo or
|
||||
redo. All commands are as follows:
|
||||
|
||||
| Command name | Description | Parameters |
|
||||
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 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 will be the operation node. If there are multiple active nodes, only the first one will be effective | |
|
||||
| INSERT_CHILD_NODE | Insert a child node, the active node will be the operation node | |
|
||||
| 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 will be the operation node | |
|
||||
| PASTE_NODE | Paste node to a node, the active node will be the operation node | data (the node data to paste, usually obtained through the renderer.copyNode() and renderer.cutNode() methods) |
|
||||
| SET_NODE_STYLE | Modify node style | node (the node to set the style of), prop (style property), value (style property value), isActive (boolean, whether the style being set is for the active state) |
|
||||
| SET_NODE_ACTIVE | Set whether the node is active | node (the node to set), active (boolean, whether to activate) |
|
||||
| CLEAR_ACTIVE_NODE | Clear the active state of the currently active node(s), the active node will be the operation node | |
|
||||
| SET_NODE_EXPAND | Set whether the node is expanded | node (the node to set), expand (boolean, whether to expand) |
|
||||
| EXPAND_ALL | Expand all nodes | |
|
||||
| UNEXPAND_ALL | Collapse all nodes | |
|
||||
| UNEXPAND_TO_LEVEL (v0.2.8+) | Expand to a specified level | level (the level to expand to, 1, 2, 3...) |
|
||||
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
|
||||
| SET_NODE_TEXT | Set node text | node (the node to set), text (the new text for the node) |
|
||||
| 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_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)) |
|
||||
| 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) |
|
||||
| ADD_GENERALIZATION (v0.2.0+) | Add a node summary | data (the data for the summary, in object format, all numerical fields of the node are supported, default is `{text: 'summary'}`) |
|
||||
| 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) |
|
||||
| Command name | Description | Parameters |
|
||||
| ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 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 will be the operation node. If there are multiple active nodes, only the first one will be effective | |
|
||||
| INSERT_CHILD_NODE | Insert a child node, the active node will be the operation node | |
|
||||
| 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 will be the operation node | |
|
||||
| PASTE_NODE | Paste node to a node, the active node will be the operation node | data (the node data to paste, usually obtained through the renderer.copyNode() and renderer.cutNode() methods) |
|
||||
| SET_NODE_STYLE | Modify node style | node (the node to set the style of), prop (style property), value (style property value), isActive (boolean, whether the style being set is for the active state) |
|
||||
| SET_NODE_ACTIVE | Set whether the node is active | node (the node to set), active (boolean, whether to activate) |
|
||||
| CLEAR_ACTIVE_NODE | Clear the active state of the currently active node(s), the active node will be the operation node | |
|
||||
| SET_NODE_EXPAND | Set whether the node is expanded | node (the node to set), expand (boolean, whether to expand) |
|
||||
| EXPAND_ALL | Expand all nodes | |
|
||||
| UNEXPAND_ALL | Collapse all nodes | |
|
||||
| UNEXPAND_TO_LEVEL (v0.2.8+) | Expand to a specified level | level (the level to expand to, 1, 2, 3...) |
|
||||
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
|
||||
| SET_NODE_TEXT | Set node text | node (the node to set), text (the new text for the node), richText(v0.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_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)) |
|
||||
| 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) |
|
||||
| ADD_GENERALIZATION (v0.2.0+) | Add a node summary | data (the data for the summary, in object format, all numerical fields of the node are supported, default is `{text: 'summary'}`) |
|
||||
| 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) |
|
||||
|
||||
### setData(data)
|
||||
|
||||
@@ -319,4 +343,16 @@ map).
|
||||
> v0.1.5+
|
||||
|
||||
Convert the coordinates of the browser's visible window to coordinates relative
|
||||
to the canvas.
|
||||
to the canvas.
|
||||
|
||||
### addPlugin(plugin, opt)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
Register plugin, Use `MindMap.usePlugin` to register plugin only before instantiation, The registered plugin will not take effect after instantiation, So if you want to register the plugin after instantiation, you can use the `addPlugin` method of the instance.
|
||||
|
||||
### removePlugin(plugin)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
Remove registered plugin, Plugins registered through the `usePlugin` or `addPlugin` methods can be removed.
|
||||
@@ -140,6 +140,34 @@
|
||||
<td>Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textAutoWrapWidth(v0.3.4+)</td>
|
||||
<td>Number</td>
|
||||
<td>500</td>
|
||||
<td>Each line of text in the node will wrap automatically when it reaches the width</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customHandleMousewheel(v0.4.3+)</td>
|
||||
<td>Function</td>
|
||||
<td>null</td>
|
||||
<td>User-defined mouse wheel event processing can pass a function, and the callback parameter is the event object</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheelAction(v0.4.3+)</td>
|
||||
<td>String</td>
|
||||
<td>zoom</td>
|
||||
<td>The behavior of the mouse wheel, <code>zoom</code>(Zoom in and out)、<code>move</code>(Move up and down). If <code>customHandleMousewheel</code> passes a custom function, this property will not take effect</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheelMoveStep(v0.4.3+)</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>When the <code>mousewheelAction</code> is set to <code>move</code>, you can use this attribute to control the step length of the view movement when the mouse scrolls. The unit is <code>px</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Watermark config</h3>
|
||||
@@ -207,12 +235,20 @@ MindMap.defineTheme(<span class="hljs-string">'Theme name'</span>, {})
|
||||
mindMap.setTheme(<span class="hljs-string">'Theme name'</span>)
|
||||
</code></pre>
|
||||
<p>For all configurations of theme, please refer to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">Default Topic</a>. The <code>defineTheme</code>method will merge the configuration you passed in with the default configuration. Most of the themes do not need custom many parts. For a typical customized theme configuration, please refer to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js">blueSky</a>.</p>
|
||||
<h3>usePlugin(plugin)</h3>
|
||||
<h3>usePlugin(plugin, opt = {})</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>opt</code>:v0.4.0+,Plugin options. If a plugin supports custom options, it can be passed in through this parameter.</li>
|
||||
</ul>
|
||||
<p>If you need to use some non-core functions, such as mini map, watermark, etc, you can register plugin through this method. Can be called in chain.</p>
|
||||
<p>Note: The plugin needs to be registered before instantiating <code>MindMap</code>.</p>
|
||||
<h3>hasPlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>Get whether a plugin is registered, The index of the plugin in the registered plugin list is returned, If it is <code>-1</code>, it means that the plugin is not registered.</p>
|
||||
<h2>Static props</h2>
|
||||
<h3>pluginList</h3>
|
||||
<blockquote>
|
||||
@@ -235,10 +271,16 @@ mindMap.setTheme(<span class="hljs-string">'Theme name'</span>)
|
||||
scaleY, <span class="hljs-comment">// Number, vertical zoom value of mind map graphics</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>render()</h3>
|
||||
<h3>render(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>: <code>v0.3.2+</code>, <code>Function</code>, Called when the re-rendering is complete</li>
|
||||
</ul>
|
||||
<p>Triggers a full rendering, which will reuse nodes for better performance. If
|
||||
only the node positions have changed, this method can be called to <code>reRender</code>.</p>
|
||||
<h3>reRender()</h3>
|
||||
<h3>reRender(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>: <code>v0.3.2+</code>, <code>Function</code>, Called when the re-rendering is complete</li>
|
||||
</ul>
|
||||
<p>Performs a full re-render, clearing the canvas and creating new nodes. This has
|
||||
poor performance and should be used sparingly.</p>
|
||||
<h3>resize()</h3>
|
||||
@@ -346,6 +388,16 @@ poor performance and should be used sparingly.</p>
|
||||
<td>e (event object), this (node instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseenter(v0.4.1+)</td>
|
||||
<td>Node mouseenter event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseleave(v0.4.1+)</td>
|
||||
<td>Node mouseleave event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_node_active</td>
|
||||
<td>Event before node activation</td>
|
||||
<td>this (node instance), activeNodeList (current list of active nodes)</td>
|
||||
@@ -385,6 +437,31 @@ poor performance and should be used sparingly.</p>
|
||||
<td>Node tree render end event</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rich_text_selection_change(v0.4.0+)</td>
|
||||
<td>Available when the <code>RichText</code> plugin is registered. Triggered when the text selection area changes when the node is edited</td>
|
||||
<td>hasRange(Whether there is a selection)、rectInfo(Size and location information of the selected area)、formatInfo(Text formatting information of the selected area)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>transforming-dom-to-images(v0.4.0+)</td>
|
||||
<td>Available when the <code>RichText</code> plugin is registered. When there is a <code>DOM</code> node in <code>svg</code>, the <code>DOM</code> node will be converted to an image when exporting to an image. This event will be triggered during the conversion process. You can use this event to prompt the user about the node to which you are currently converting</td>
|
||||
<td>index(Index of the node currently converted to)、len(Total number of nodes to be converted)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dragging(v0.4.5+)</td>
|
||||
<td>Triggered when a node is dragged</td>
|
||||
<td>node(The currently dragged node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dragend(v0.4.5+)</td>
|
||||
<td>Triggered when the node is dragged and ends</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>associative_line_click(v0.4.5+)</td>
|
||||
<td>Triggered when an associated line is clicked</td>
|
||||
<td>path(Connector node)、clickPath(Invisible click line node)、node(Start node)、toNode(Target node)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
@@ -524,7 +601,7 @@ redo. All commands are as follows:</p>
|
||||
<tr>
|
||||
<td>SET_NODE_TEXT</td>
|
||||
<td>Set node text</td>
|
||||
<td>node (the node to set), text (the new text for the node)</td>
|
||||
<td>node (the node to set), text (the new text for the node), richText(v0.4.0+, If you want to set a rich text character, you need to set it to <code>true</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_IMAGE</td>
|
||||
@@ -628,6 +705,16 @@ map).</p>
|
||||
</blockquote>
|
||||
<p>Convert the coordinates of the browser's visible window to coordinates relative
|
||||
to the canvas.</p>
|
||||
<h3>addPlugin(plugin, opt)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>Register plugin, Use <code>MindMap.usePlugin</code> to register plugin only before instantiation, The registered plugin will not take effect after instantiation, So if you want to register the plugin after instantiation, you can use the <code>addPlugin</code> method of the instance.</p>
|
||||
<h3>removePlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>Remove registered plugin, Plugins registered through the <code>usePlugin</code> or <code>addPlugin</code> methods can be removed.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -20,19 +20,40 @@ After registration and instantiation of `MindMap`, the instance can be obtained
|
||||
Exports as `png`, an async method that returns image data, `data:url` data which
|
||||
can be downloaded or displayed.
|
||||
|
||||
### svg()
|
||||
### svg(name, domToImage = false, plusCssText)
|
||||
|
||||
- `name`:`svg` title
|
||||
|
||||
- `domToImage`:v0.4.0+, When node rich text editing is enabled, you can use this parameter to specify whether to convert the `dom` node in the `svg` into a picture
|
||||
|
||||
- `plusCssText`:v0.4.0+, When node rich text editing is enabled and `domToImage` passes `false`, additional `css` styles can be added. If there is a `dom` node in `svg`, you can set some styles for the node through this parameter, such as:
|
||||
|
||||
```js
|
||||
svg(
|
||||
'',
|
||||
false,
|
||||
`* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}`
|
||||
)
|
||||
```
|
||||
|
||||
Exports as `svg`, an async method that returns `svg` data, `data:url` data which
|
||||
can be downloaded or displayed.
|
||||
|
||||
### getSvgData()
|
||||
### getSvgData(domToImage)
|
||||
|
||||
- `domToImage`:v0.4.0+, If node rich text is enabled, you can use this parameter to specify whether to convert the `DOM` node embedded in `svg` into a picture.
|
||||
|
||||
Gets `svg` data, an async method that returns an object:
|
||||
|
||||
```js
|
||||
{
|
||||
node; // svg object
|
||||
str; // svg string
|
||||
str; // svg string, if rich text editing is enabled and domToImage is set to true, the dom node in the svg character returned by this value will be converted into the form of an image
|
||||
nodeWithDomToImg// v0.4.0+,The svg object after the DOM node is converted to an image has a value only when rich text editing is enabled and domToImage is set to true, otherwise null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -13,14 +13,39 @@ MindMap.usePlugin(Export)
|
||||
<h3>png()</h3>
|
||||
<p>Exports as <code>png</code>, an async method that returns image data, <code>data:url</code> data which
|
||||
can be downloaded or displayed.</p>
|
||||
<h3>svg()</h3>
|
||||
<h3>svg(name, domToImage = false, plusCssText)</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>name</code>:<code>svg</code> title</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>domToImage</code>:v0.4.0+, When node rich text editing is enabled, you can use this parameter to specify whether to convert the <code>dom</code> node in the <code>svg</code> into a picture</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>plusCssText</code>:v0.4.0+, When node rich text editing is enabled and <code>domToImage</code> passes <code>false</code>, additional <code>css</code> styles can be added. If there is a <code>dom</code> node in <code>svg</code>, you can set some styles for the node through this parameter, such as:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>svg(
|
||||
<span class="hljs-string">''</span>,
|
||||
<span class="hljs-literal">false</span>,
|
||||
<span class="hljs-string">`* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}`</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>Exports as <code>svg</code>, an async method that returns <code>svg</code> data, <code>data:url</code> data which
|
||||
can be downloaded or displayed.</p>
|
||||
<h3>getSvgData()</h3>
|
||||
<h3>getSvgData(domToImage)</h3>
|
||||
<ul>
|
||||
<li><code>domToImage</code>:v0.4.0+, If node rich text is enabled, you can use this parameter to specify whether to convert the <code>DOM</code> node embedded in <code>svg</code> into a picture.</li>
|
||||
</ul>
|
||||
<p>Gets <code>svg</code> data, an async method that returns an object:</p>
|
||||
<pre class="hljs"><code>{
|
||||
node; <span class="hljs-comment">// svg object</span>
|
||||
str; <span class="hljs-comment">// svg string</span>
|
||||
str; <span class="hljs-comment">// svg string, if rich text editing is enabled and domToImage is set to true, the dom node in the svg character returned by this value will be converted into the form of an image</span>
|
||||
nodeWithDomToImg<span class="hljs-comment">// v0.4.0+,The svg object after the DOM node is converted to an image has a value only when rich text editing is enabled and domToImage is set to true, otherwise null</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>pdf(name)</h3>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
- [x] Supports various node shapes
|
||||
- [x] Supports export to json, png, svg, pdf, and import from json, xmind
|
||||
- [x] Supports mini map、support watermark
|
||||
- [x] Supports associative lines
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -50,16 +51,16 @@ Provide document page service.
|
||||
|
||||
The folder containing the packaged resources for the `web` folder.
|
||||
|
||||
4.`docs`
|
||||
|
||||
Documentation, etc.
|
||||
|
||||
## Related Articles
|
||||
|
||||
[Technical Analysis of Web Mind Map Implementation (chi)](https://juejin.cn/post/6987711560521089061)
|
||||
|
||||
[Only a hundred lines of code are needed to add local file operation capability to your Web page. Are you sure not to try?](https://juejin.cn/post/7157681502506090510)
|
||||
|
||||
[When you press the direction key, how does the TV find the next focus](https://juejin.cn/post/7199666255883927612)
|
||||
|
||||
[How to simulate the background image style of css in canvas](https://juejin.cn/post/7204854015463538744)
|
||||
|
||||
## Special Note
|
||||
|
||||
This project is rough and has not been thoroughly tested, its features are not
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
<p><code>simple-mind-map</code> is a simple and powerful web mind map library, not dependent on any specific framework.</p>
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox17" checked="true"><label for="checkbox17">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="checkbox18" checked="true"><label for="checkbox18">Supports four types of structures: logical structure diagrams, mind maps,</label>
|
||||
<li><input type="checkbox" id="checkbox36" checked="true"><label for="checkbox36">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="checkbox37" checked="true"><label for="checkbox37">Supports four types of structures: logical structure diagrams, mind maps,</label>
|
||||
organizational structure diagrams, and directory organization diagrams</li>
|
||||
<li><input type="checkbox" id="checkbox19" checked="true"><label for="checkbox19">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox20" checked="true"><label for="checkbox20">Supports shortcuts</label></li>
|
||||
<li><input type="checkbox" id="checkbox21" checked="true"><label for="checkbox21">Node content supports images, icons, hyperlinks, notes, tags, and</label>
|
||||
<li><input type="checkbox" id="checkbox38" checked="true"><label for="checkbox38">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox39" checked="true"><label for="checkbox39">Supports shortcuts</label></li>
|
||||
<li><input type="checkbox" id="checkbox40" checked="true"><label for="checkbox40">Node content supports images, icons, hyperlinks, notes, tags, and</label>
|
||||
summaries</li>
|
||||
<li><input type="checkbox" id="checkbox22" checked="true"><label for="checkbox22">Supports forward and backward navigation</label></li>
|
||||
<li><input type="checkbox" id="checkbox23" checked="true"><label for="checkbox23">Supports dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox24" checked="true"><label for="checkbox24">Supports right-click and Ctrl + left-click to select multiple items</label></li>
|
||||
<li><input type="checkbox" id="checkbox25" checked="true"><label for="checkbox25">Supports free dragging and dragging to adjust nodes</label></li>
|
||||
<li><input type="checkbox" id="checkbox26" checked="true"><label for="checkbox26">Supports various node shapes</label></li>
|
||||
<li><input type="checkbox" id="checkbox27" checked="true"><label for="checkbox27">Supports export to json, png, svg, pdf, and import from json, xmind</label></li>
|
||||
<li><input type="checkbox" id="checkbox28" checked="true"><label for="checkbox28">Supports mini map、support watermark</label></li>
|
||||
<li><input type="checkbox" id="checkbox41" checked="true"><label for="checkbox41">Supports forward and backward navigation</label></li>
|
||||
<li><input type="checkbox" id="checkbox42" checked="true"><label for="checkbox42">Supports dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox43" checked="true"><label for="checkbox43">Supports right-click and Ctrl + left-click to select multiple items</label></li>
|
||||
<li><input type="checkbox" id="checkbox44" checked="true"><label for="checkbox44">Supports free dragging and dragging to adjust nodes</label></li>
|
||||
<li><input type="checkbox" id="checkbox45" checked="true"><label for="checkbox45">Supports various node shapes</label></li>
|
||||
<li><input type="checkbox" id="checkbox46" checked="true"><label for="checkbox46">Supports export to json, png, svg, pdf, and import from json, xmind</label></li>
|
||||
<li><input type="checkbox" id="checkbox47" checked="true"><label for="checkbox47">Supports mini map、support watermark</label></li>
|
||||
<li><input type="checkbox" id="checkbox48" checked="true"><label for="checkbox48">Supports associative lines</label></li>
|
||||
</ul>
|
||||
<h2>Table of Contents</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
@@ -27,27 +28,27 @@ 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="checkbox29" checked="true"><label for="checkbox29">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
<li><input type="checkbox" id="checkbox49" checked="true"><label for="checkbox49">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
images, icons, hyperlinks, notes, tags, and summaries</li>
|
||||
<li><input type="checkbox" id="checkbox30" checked="true"><label for="checkbox30">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
<li><input type="checkbox" id="checkbox50" checked="true"><label for="checkbox50">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
outline, theme selection, and structure selection</li>
|
||||
<li><input type="checkbox" id="checkbox31" checked="true"><label for="checkbox31">Import and export functionality; data is saved in the browser's local</label>
|
||||
<li><input type="checkbox" id="checkbox51" checked="true"><label for="checkbox51">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="checkbox32" checked="true"><label for="checkbox32">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
<li><input type="checkbox" id="checkbox52" checked="true"><label for="checkbox52">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
and organizing layout</li>
|
||||
<li><input type="checkbox" id="checkbox33" checked="true"><label for="checkbox33">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
<li><input type="checkbox" id="checkbox53" checked="true"><label for="checkbox53">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>
|
||||
<p>Provide document page service.</p>
|
||||
<p>3.<code>dist</code></p>
|
||||
<p>The folder containing the packaged resources for the <code>web</code> folder.</p>
|
||||
<p>4.<code>docs</code></p>
|
||||
<p>Documentation, etc.</p>
|
||||
<h2>Related Articles</h2>
|
||||
<p><a href="https://juejin.cn/post/6987711560521089061">Technical Analysis of Web Mind Map Implementation (chi)</a></p>
|
||||
<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>
|
||||
<h2>Special Note</h2>
|
||||
<p>This project is rough and has not been thoroughly tested, its features are not
|
||||
yet fully developed, and there are some performance issues, especially when the number of nodes is large. It is only for
|
||||
|
||||
@@ -121,7 +121,9 @@ if `key` is not passed, return the `data` object
|
||||
Set the value of the specified key in the data object of the node's real data
|
||||
nodeData, `SET_NODE_DATA` command's shortcut method
|
||||
|
||||
### setText(text)
|
||||
### setText(text, richText)
|
||||
|
||||
- `richText`: v0.4.2+,`Boolean`, If you want to set rich text content, that is, `html` character, `richText` needs to be passed `true`
|
||||
|
||||
Setting the node text, a shortcut for the `SET_NODE_TEXT` command
|
||||
|
||||
|
||||
@@ -67,7 +67,10 @@ if <code>key</code> is not passed, return the <code>data</code> object</p>
|
||||
<h3>setData(data)</h3>
|
||||
<p>Set the value of the specified key in the data object of the node's real data
|
||||
nodeData, <code>SET_NODE_DATA</code> command's shortcut method</p>
|
||||
<h3>setText(text)</h3>
|
||||
<h3>setText(text, richText)</h3>
|
||||
<ul>
|
||||
<li><code>richText</code>: v0.4.2+,<code>Boolean</code>, If you want to set rich text content, that is, <code>html</code> character, <code>richText</code> needs to be passed <code>true</code></li>
|
||||
</ul>
|
||||
<p>Setting the node text, a shortcut for the <code>SET_NODE_TEXT</code> command</p>
|
||||
<h3>setImage(imgData)</h3>
|
||||
<p>Setting the node image, a shortcut for the <code>SET_NODE_IMAGE</code> command</p>
|
||||
|
||||
153
web/src/pages/Doc/en/richText/index.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# RichText plugin
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
> Note: This is a testing nature and imperfect function
|
||||
|
||||
This plugin provides the ability to edit rich text of nodes, and takes effect after registration.
|
||||
|
||||
By default, node editing can only uniformly apply styles to all text in the node. This plugin can support rich text editing effects. Currently, it supports bold, italic, underline, strikethrough, font, font size, color, and backgroundColor. Underline and line height are not supported.
|
||||
|
||||
The principle of this plugin is to use [Quill](https://github.com/quilljs/quill) editor implements rich text editing, and then uses the edited `DOM` node directly as the text data of the node, and embeds the `DOM` node through the `svg` `foreignObject` tag during rendering.
|
||||
|
||||
This also caused a problem, that is, the function of exporting as a picture was affected, The original principle of exporting `svg` as an image is very simple, Get the `svg` string, and then create the `blob` data of the `type=image/svg+xml` type. Then use the `URL.createObjectURL` method to generate the `data:url` data. Then create a `Image` tag, use the `data:url` as the `src` of the image, and finally draw the image on the `canvas` object for export, However, after testing, when the `DOM` node is embedded in the `svg`, this method of export will cause errors, and after trying many ways, the perfect export effect cannot be achieved, The current method is to traverse the `foreignObject` node in `svg`, using [html2canvas](https://github.com/niklasvh/html2canvas) Convert the `DOM` node in the `foreignObject` node into an image and then replace the `foreignObject` node. This method can work, but it is very time-consuming. Because the `html2canvas` conversion takes a long time, it takes about 2 seconds to convert a node. This leads to the more nodes, the slower the conversion time. Therefore, it is recommended not to use this plugin if you cannot tolerate the long time of export.
|
||||
|
||||
If you have a better way, please leave a message.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import RichText from 'simple-mind-map/src/RichText.js'
|
||||
|
||||
MindMap.usePlugin(RichText, opt?)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.richText`.
|
||||
|
||||
### Register options
|
||||
|
||||
The `opt` option can pass the following parameters:
|
||||
|
||||
- `opt.fontFamilyList`
|
||||
|
||||
Replace the built-in font list during rich text editing. The built-in list is:
|
||||
|
||||
```js
|
||||
[
|
||||
'宋体, SimSun, Songti SC',
|
||||
'微软雅黑, Microsoft YaHei',
|
||||
'楷体, 楷体_GB2312, SimKai, STKaiti',
|
||||
'黑体, SimHei, Heiti SC',
|
||||
'隶书, SimLi',
|
||||
'andale mono',
|
||||
'arial, helvetica, sans-serif',
|
||||
'arial black, avant garde',
|
||||
'comic sans ms',
|
||||
'impact, chicago',
|
||||
'times new roman',
|
||||
'sans-serif',
|
||||
'serif'
|
||||
]
|
||||
```
|
||||
|
||||
- `opt.fontSizeList`
|
||||
|
||||
Replace the built-in font size list during rich text editing. The built-in list is:
|
||||
|
||||
```js
|
||||
[1, 2, 3, ...100]
|
||||
```
|
||||
|
||||
## Method
|
||||
|
||||
### selectAll()
|
||||
|
||||
Select All. When the node is being edited, you can select all the text in the node through this method.
|
||||
|
||||
### formatText(config = {})
|
||||
|
||||
- `config`:Object. The key is the style attribute and the value is the style value. The complete configuration is as follows:
|
||||
|
||||
```js
|
||||
{
|
||||
font: '字体',
|
||||
size: '12px,' // font size
|
||||
bold: true, // Bold or not, true/false
|
||||
italic: true, // Italic or not, true/false
|
||||
underline: true, // Show underline or not, true/false
|
||||
strike: true, // Whether to display strikethrough, true/false
|
||||
color: '#333' // color
|
||||
}
|
||||
```
|
||||
|
||||
Formats the currently selected text.
|
||||
|
||||
### formatRangeText(range, config = {})
|
||||
|
||||
- `range`:The range object of `Quill`, has the following format:
|
||||
|
||||
```js
|
||||
{
|
||||
index,
|
||||
length
|
||||
}
|
||||
```
|
||||
|
||||
- `config`:Same as `formatText` method
|
||||
|
||||
Formats the text of the specified range.
|
||||
|
||||
### formatAllText(config = {})
|
||||
|
||||
- `config`:Same as `formatText` method
|
||||
|
||||
Formats all text of the current edit node.
|
||||
|
||||
### removeFormat()
|
||||
|
||||
> v0.4.1+
|
||||
|
||||
Clears the style of the currently selected text.
|
||||
|
||||
### normalStyleToRichTextStyle(style)
|
||||
|
||||
Converts a normal node style object to a rich text style object. Because there are differences between node style attributes and rich text style attributes during non-rich text editing, a conversion operation is required. For example:
|
||||
|
||||
```js
|
||||
{
|
||||
fontFamily: 'xxx'
|
||||
}
|
||||
|
||||
// After conversion
|
||||
|
||||
{
|
||||
font: 'xxx'
|
||||
}
|
||||
```
|
||||
|
||||
### richTextStyleToNormalStyle(config)
|
||||
|
||||
Converts rich text style objects to normal node style objects. For example:
|
||||
|
||||
```js
|
||||
{
|
||||
size: '16px'
|
||||
}
|
||||
|
||||
// After conversion
|
||||
|
||||
{
|
||||
fontSize: 16
|
||||
}
|
||||
```
|
||||
|
||||
### handleSvgDomElements(svg)
|
||||
|
||||
- `svg`: `svg` node
|
||||
|
||||
Convert the `dom` element embedded in the `svg` into a picture and return a `Promise`.
|
||||
|
||||
### transformAllNodesToNormalNode()
|
||||
|
||||
Convert all nodes to non-rich text nodes.
|
||||
134
web/src/pages/Doc/en/richText/index.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>RichText plugin</h1>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>Note: This is a testing nature and imperfect function</p>
|
||||
</blockquote>
|
||||
<p>This plugin provides the ability to edit rich text of nodes, and takes effect after registration.</p>
|
||||
<p>By default, node editing can only uniformly apply styles to all text in the node. This plugin can support rich text editing effects. Currently, it supports bold, italic, underline, strikethrough, font, font size, color, and backgroundColor. Underline and line height are not supported.</p>
|
||||
<p>The principle of this plugin is to use <a href="https://github.com/quilljs/quill">Quill</a> editor implements rich text editing, and then uses the edited <code>DOM</code> node directly as the text data of the node, and embeds the <code>DOM</code> node through the <code>svg</code> <code>foreignObject</code> tag during rendering.</p>
|
||||
<p>This also caused a problem, that is, the function of exporting as a picture was affected, The original principle of exporting <code>svg</code> as an image is very simple, Get the <code>svg</code> string, and then create the <code>blob</code> data of the <code>type=image/svg+xml</code> type. Then use the <code>URL.createObjectURL</code> method to generate the <code>data:url</code> data. Then create a <code>Image</code> tag, use the <code>data:url</code> as the <code>src</code> of the image, and finally draw the image on the <code>canvas</code> object for export, However, after testing, when the <code>DOM</code> node is embedded in the <code>svg</code>, this method of export will cause errors, and after trying many ways, the perfect export effect cannot be achieved, The current method is to traverse the <code>foreignObject</code> node in <code>svg</code>, using <a href="https://github.com/niklasvh/html2canvas">html2canvas</a> Convert the <code>DOM</code> node in the <code>foreignObject</code> node into an image and then replace the <code>foreignObject</code> node. This method can work, but it is very time-consuming. Because the <code>html2canvas</code> conversion takes a long time, it takes about 2 seconds to convert a node. This leads to the more nodes, the slower the conversion time. Therefore, it is recommended not to use this plugin if you cannot tolerate the long time of export.</p>
|
||||
<p>If you have a better way, please leave a message.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> RichText <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/RichText.js'</span>
|
||||
|
||||
MindMap.usePlugin(RichText, opt?)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.richText</code>.</p>
|
||||
<h3>Register options</h3>
|
||||
<p>The <code>opt</code> option can pass the following parameters:</p>
|
||||
<ul>
|
||||
<li><code>opt.fontFamilyList</code></li>
|
||||
</ul>
|
||||
<p>Replace the built-in font list during rich text editing. The built-in list is:</p>
|
||||
<pre class="hljs"><code>[
|
||||
<span class="hljs-string">'宋体, SimSun, Songti SC'</span>,
|
||||
<span class="hljs-string">'微软雅黑, Microsoft YaHei'</span>,
|
||||
<span class="hljs-string">'楷体, 楷体_GB2312, SimKai, STKaiti'</span>,
|
||||
<span class="hljs-string">'黑体, SimHei, Heiti SC'</span>,
|
||||
<span class="hljs-string">'隶书, SimLi'</span>,
|
||||
<span class="hljs-string">'andale mono'</span>,
|
||||
<span class="hljs-string">'arial, helvetica, sans-serif'</span>,
|
||||
<span class="hljs-string">'arial black, avant garde'</span>,
|
||||
<span class="hljs-string">'comic sans ms'</span>,
|
||||
<span class="hljs-string">'impact, chicago'</span>,
|
||||
<span class="hljs-string">'times new roman'</span>,
|
||||
<span class="hljs-string">'sans-serif'</span>,
|
||||
<span class="hljs-string">'serif'</span>
|
||||
]
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li><code>opt.fontSizeList</code></li>
|
||||
</ul>
|
||||
<p>Replace the built-in font size list during rich text editing. The built-in list is:</p>
|
||||
<pre class="hljs"><code>[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, ..<span class="hljs-number">.100</span>]
|
||||
</code></pre>
|
||||
<h2>Method</h2>
|
||||
<h3>selectAll()</h3>
|
||||
<p>Select All. When the node is being edited, you can select all the text in the node through this method.</p>
|
||||
<h3>formatText(config = {})</h3>
|
||||
<ul>
|
||||
<li><code>config</code>:Object. The key is the style attribute and the value is the style value. The complete configuration is as follows:</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">font</span>: <span class="hljs-string">'字体'</span>,
|
||||
<span class="hljs-attr">size</span>: <span class="hljs-string">'12px,'</span> <span class="hljs-comment">// font size</span>
|
||||
<span class="hljs-attr">bold</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Bold or not, true/false </span>
|
||||
<span class="hljs-attr">italic</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Italic or not, true/false </span>
|
||||
<span class="hljs-attr">underline</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Show underline or not, true/false </span>
|
||||
<span class="hljs-attr">strike</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Whether to display strikethrough, true/false </span>
|
||||
<span class="hljs-attr">color</span>: <span class="hljs-string">'#333'</span> <span class="hljs-comment">// color</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Formats the currently selected text.</p>
|
||||
<h3>formatRangeText(range, config = {})</h3>
|
||||
<ul>
|
||||
<li><code>range</code>:The range object of <code>Quill</code>, has the following format:</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
index,
|
||||
length
|
||||
}
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li><code>config</code>:Same as <code>formatText</code> method</li>
|
||||
</ul>
|
||||
<p>Formats the text of the specified range.</p>
|
||||
<h3>formatAllText(config = {})</h3>
|
||||
<ul>
|
||||
<li><code>config</code>:Same as <code>formatText</code> method</li>
|
||||
</ul>
|
||||
<p>Formats all text of the current edit node.</p>
|
||||
<h3>removeFormat()</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.1+</p>
|
||||
</blockquote>
|
||||
<p>Clears the style of the currently selected text.</p>
|
||||
<h3>normalStyleToRichTextStyle(style)</h3>
|
||||
<p>Converts a normal node style object to a rich text style object. Because there are differences between node style attributes and rich text style attributes during non-rich text editing, a conversion operation is required. For example:</p>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">fontFamily</span>: <span class="hljs-string">'xxx'</span>
|
||||
}
|
||||
|
||||
<span class="hljs-comment">// After conversion</span>
|
||||
|
||||
{
|
||||
<span class="hljs-attr">font</span>: <span class="hljs-string">'xxx'</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>richTextStyleToNormalStyle(config)</h3>
|
||||
<p>Converts rich text style objects to normal node style objects. For example:</p>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">size</span>: <span class="hljs-string">'16px'</span>
|
||||
}
|
||||
|
||||
<span class="hljs-comment">// After conversion</span>
|
||||
|
||||
{
|
||||
<span class="hljs-attr">fontSize</span>: <span class="hljs-number">16</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>handleSvgDomElements(svg)</h3>
|
||||
<ul>
|
||||
<li><code>svg</code>: <code>svg</code> node</li>
|
||||
</ul>
|
||||
<p>Convert the <code>dom</code> element embedded in the <code>svg</code> into a picture and return a <code>Promise</code>.</p>
|
||||
<h3>transformAllNodesToNormalNode()</h3>
|
||||
<p>Convert all nodes to non-rich text nodes.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -109,6 +109,22 @@ Angle to radian
|
||||
|
||||
CamelCase to hyphen
|
||||
|
||||
#### joinFontStr({ italic, bold, fontSize, fontFamily })
|
||||
|
||||
> v0.3.4+
|
||||
|
||||
Join the `font` attribute value of the `css` font
|
||||
|
||||
#### measureText(text, { italic, bold, fontSize, fontFamily })
|
||||
|
||||
> v0.3.4+
|
||||
|
||||
Measure the width and height of the text, return value:
|
||||
|
||||
```js
|
||||
{ width, height }
|
||||
```
|
||||
|
||||
## Simulate CSS background in Canvas
|
||||
|
||||
Import:
|
||||
|
||||
@@ -62,6 +62,18 @@ and copying the <code>data</code> of the data object, example:</p>
|
||||
<p>v0.2.24+</p>
|
||||
</blockquote>
|
||||
<p>CamelCase to hyphen</p>
|
||||
<h4>joinFontStr({ italic, bold, fontSize, fontFamily })</h4>
|
||||
<blockquote>
|
||||
<p>v0.3.4+</p>
|
||||
</blockquote>
|
||||
<p>Join the <code>font</code> attribute value of the <code>css</code> font</p>
|
||||
<h4>measureText(text, { italic, bold, fontSize, fontFamily })</h4>
|
||||
<blockquote>
|
||||
<p>v0.3.4+</p>
|
||||
</blockquote>
|
||||
<p>Measure the width and height of the text, return value:</p>
|
||||
<pre class="hljs"><code>{ width, height }
|
||||
</code></pre>
|
||||
<h2>Simulate CSS background in Canvas</h2>
|
||||
<p>Import:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'</span>
|
||||
|
||||
@@ -41,4 +41,10 @@ mindMap.watermark.updateWatermark({
|
||||
fontSize: 20
|
||||
}
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
### hasWatermark()
|
||||
|
||||
> v0.3.2+
|
||||
|
||||
Gets whether the watermark exists.
|
||||
@@ -31,6 +31,11 @@ MindMap.usePlugin(Watermark)
|
||||
}
|
||||
})
|
||||
</code></pre>
|
||||
<h3>hasWatermark()</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.2+</p>
|
||||
</blockquote>
|
||||
<p>Gets whether the watermark exists.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
|
||||
export default [{"lang":"zh","children":[{"path":"batchExecution","title":"BatchExecution实例"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"Command实例"},{"path":"constructor","title":"构造函数"},{"path":"doExport","title":"Export 插件"},{"path":"drag","title":"Drag插件"},{"path":"introduction","title":"简介"},{"path":"keyboardNavigation","title":"KeyboardNavigation插件"},{"path":"keyCommand","title":"KeyCommand实例"},{"path":"miniMap","title":"MiniMap插件"},{"path":"node","title":"Node实例"},{"path":"render","title":"Render实例"},{"path":"select","title":"Select 插件 "},{"path":"start","title":"开始"},{"path":"translate","title":"参与翻译"},{"path":"utils","title":"内置工具方法"},{"path":"view","title":"View实例"},{"path":"watermark","title":"Watermark插件"},{"path":"xmind","title":"XMind解析"}]},{"lang":"en","children":[{"path":"batchExecution","title":"batchExecution instance"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"command instance"},{"path":"constructor","title":"Constructor"},{"path":"doExport","title":"Export plugin"},{"path":"drag","title":"Drag plugin"},{"path":"introduction","title":"Introduction"},{"path":"keyboardNavigation","title":"KeyboardNavigation plugin"},{"path":"keyCommand","title":"KeyCommand instance"},{"path":"miniMap","title":"MiniMap plugin"},{"path":"node","title":"Node instance"},{"path":"render","title":"Render instance"},{"path":"select","title":"Select plugin"},{"path":"start","title":"Start"},{"path":"translate","title":"Participate in translation"},{"path":"utils","title":"Utility Methods"},{"path":"view","title":"View instance"},{"path":"watermark","title":"Watermark plugin"},{"path":"xmind","title":"XMind parse"}]}]
|
||||
export default [{"lang":"zh","children":[{"path":"associativeLine","title":"AssociativeLine 插件"},{"path":"batchExecution","title":"BatchExecution实例"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"Command实例"},{"path":"constructor","title":"构造函数"},{"path":"doExport","title":"Export 插件"},{"path":"drag","title":"Drag插件"},{"path":"introduction","title":"简介"},{"path":"keyboardNavigation","title":"KeyboardNavigation插件"},{"path":"keyCommand","title":"KeyCommand实例"},{"path":"miniMap","title":"MiniMap插件"},{"path":"node","title":"Node实例"},{"path":"render","title":"Render实例"},{"path":"richText","title":"RichText插件"},{"path":"select","title":"Select 插件 "},{"path":"start","title":"开始"},{"path":"translate","title":"参与翻译"},{"path":"utils","title":"内置工具方法"},{"path":"view","title":"View实例"},{"path":"watermark","title":"Watermark插件"},{"path":"xmind","title":"XMind解析"}]},{"lang":"en","children":[{"path":"associativeLine","title":"AssociativeLine plugin"},{"path":"batchExecution","title":"batchExecution instance"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"command instance"},{"path":"constructor","title":"Constructor"},{"path":"doExport","title":"Export plugin"},{"path":"drag","title":"Drag plugin"},{"path":"introduction","title":"Introduction"},{"path":"keyboardNavigation","title":"KeyboardNavigation plugin"},{"path":"keyCommand","title":"KeyCommand instance"},{"path":"miniMap","title":"MiniMap plugin"},{"path":"node","title":"Node instance"},{"path":"render","title":"Render instance"},{"path":"richText","title":"RichText plugin"},{"path":"select","title":"Select plugin"},{"path":"start","title":"Start"},{"path":"translate","title":"Participate in translation"},{"path":"utils","title":"Utility Methods"},{"path":"view","title":"View instance"},{"path":"watermark","title":"Watermark plugin"},{"path":"xmind","title":"XMind parse"}]}]
|
||||
|
||||
87
web/src/pages/Doc/zh/associativeLine/index.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# AssociativeLine 插件
|
||||
|
||||
> v0.4.5+
|
||||
|
||||
该插件用于支持添加关联线。
|
||||
|
||||
该插件目前功能比较简陋,不支持修改关联线的控制点,不支持在关联线上添加文字。
|
||||
|
||||
## 注册
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import AssociativeLine from 'simple-mind-map/src/AssociativeLine.js'
|
||||
|
||||
MindMap.usePlugin(AssociativeLine)
|
||||
```
|
||||
|
||||
注册完且实例化`MindMap`后可通过`mindMap.associativeLine`获取到该实例。
|
||||
|
||||
## 配置
|
||||
|
||||
支持修改关联线的粗细和颜色,分为默认状态和激活状态。配置如下:
|
||||
|
||||
- `associativeLineWidth`:关联线默认状态的粗细,默认值为`2`
|
||||
|
||||
- `associativeLineColor`:关联线默认状态的颜色,默认值为`rgb(51, 51, 51)`
|
||||
|
||||
- `associativeLineActiveWidth`:关联线激活状态的粗细,默认值为`8`
|
||||
|
||||
- `associativeLineActiveColor`:关联线激活状态的颜色,默认值为`rgba(2, 167, 240, 1)`
|
||||
|
||||
配置以主题的方式提供,所以如果想要修改这四个属性,可以通过`mindMap.setThemeConfig(config)`方法进行修改。
|
||||
|
||||
## 属性
|
||||
|
||||
### mindMap.associativeLine.lineList
|
||||
|
||||
当前所有连接线数据,数组类型,数组的每一项也是一个数组:
|
||||
|
||||
```js
|
||||
[
|
||||
path, // 连接线节点
|
||||
clickPath, // 不可见的点击线节点
|
||||
node, // 起始节点
|
||||
toNode // 目标节点
|
||||
]
|
||||
```
|
||||
|
||||
### mindMap.associativeLine.activeLine
|
||||
|
||||
当前激活的连接线,数组类型,同`lineList`数组的每一项的结构。
|
||||
|
||||
## 方法
|
||||
|
||||
### renderAllLines()
|
||||
|
||||
重新渲染所有关联线。
|
||||
|
||||
### removeAllLines()
|
||||
|
||||
移除所有关联线。
|
||||
|
||||
### createLineFromActiveNode()
|
||||
|
||||
从当前激活节点开始创建关联线,如果有多个激活节点,默认为第一个节点。
|
||||
|
||||
调用该方法后,会从第一个激活节点到当前鼠标实时位置渲染一条关联线,当点击某个目标节点后则代表创建完成,会在第一个激活节点和点击节点之间渲染一条关联线。
|
||||
|
||||
### createLine(fromNode)
|
||||
|
||||
从指定节点开始创建关联线。
|
||||
|
||||
调用该方法后,会从指定节点到当前鼠标实时位置渲染一条关联线,当点击某个目标节点后则代表创建完成,会在指定节点和点击节点之间渲染一条关联线。
|
||||
|
||||
### addLine(fromNode, toNode)
|
||||
|
||||
直接添加一条关联线。
|
||||
|
||||
调用该方法,会直接创建一条从`fromNode`到`toNode`节点的关联线。
|
||||
|
||||
### removeLine()
|
||||
|
||||
删除当前激活的关联线。点击某条关联线则视为激活。
|
||||
|
||||
### clearActiveLine()
|
||||
|
||||
清除当前激活的关联线的激活状态。
|
||||
75
web/src/pages/Doc/zh/associativeLine/index.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>AssociativeLine 插件</h1>
|
||||
<blockquote>
|
||||
<p>v0.4.5+</p>
|
||||
</blockquote>
|
||||
<p>该插件用于支持添加关联线。</p>
|
||||
<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">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/AssociativeLine.js'</span>
|
||||
|
||||
MindMap.usePlugin(AssociativeLine)
|
||||
</code></pre>
|
||||
<p>注册完且实例化<code>MindMap</code>后可通过<code>mindMap.associativeLine</code>获取到该实例。</p>
|
||||
<h2>配置</h2>
|
||||
<p>支持修改关联线的粗细和颜色,分为默认状态和激活状态。配置如下:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>associativeLineWidth</code>:关联线默认状态的粗细,默认值为<code>2</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineColor</code>:关联线默认状态的颜色,默认值为<code>rgb(51, 51, 51)</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineActiveWidth</code>:关联线激活状态的粗细,默认值为<code>8</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>associativeLineActiveColor</code>:关联线激活状态的颜色,默认值为<code>rgba(2, 167, 240, 1)</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>配置以主题的方式提供,所以如果想要修改这四个属性,可以通过<code>mindMap.setThemeConfig(config)</code>方法进行修改。</p>
|
||||
<h2>属性</h2>
|
||||
<h3>mindMap.associativeLine.lineList</h3>
|
||||
<p>当前所有连接线数据,数组类型,数组的每一项也是一个数组:</p>
|
||||
<pre class="hljs"><code>[
|
||||
path, <span class="hljs-comment">// 连接线节点</span>
|
||||
clickPath, <span class="hljs-comment">// 不可见的点击线节点</span>
|
||||
node, <span class="hljs-comment">// 起始节点</span>
|
||||
toNode <span class="hljs-comment">// 目标节点</span>
|
||||
]
|
||||
</code></pre>
|
||||
<h3>mindMap.associativeLine.activeLine</h3>
|
||||
<p>当前激活的连接线,数组类型,同<code>lineList</code>数组的每一项的结构。</p>
|
||||
<h2>方法</h2>
|
||||
<h3>renderAllLines()</h3>
|
||||
<p>重新渲染所有关联线。</p>
|
||||
<h3>removeAllLines()</h3>
|
||||
<p>移除所有关联线。</p>
|
||||
<h3>createLineFromActiveNode()</h3>
|
||||
<p>从当前激活节点开始创建关联线,如果有多个激活节点,默认为第一个节点。</p>
|
||||
<p>调用该方法后,会从第一个激活节点到当前鼠标实时位置渲染一条关联线,当点击某个目标节点后则代表创建完成,会在第一个激活节点和点击节点之间渲染一条关联线。</p>
|
||||
<h3>createLine(fromNode)</h3>
|
||||
<p>从指定节点开始创建关联线。</p>
|
||||
<p>调用该方法后,会从指定节点到当前鼠标实时位置渲染一条关联线,当点击某个目标节点后则代表创建完成,会在指定节点和点击节点之间渲染一条关联线。</p>
|
||||
<h3>addLine(fromNode, toNode)</h3>
|
||||
<p>直接添加一条关联线。</p>
|
||||
<p>调用该方法,会直接创建一条从<code>fromNode</code>到<code>toNode</code>节点的关联线。</p>
|
||||
<h3>removeLine()</h3>
|
||||
<p>删除当前激活的关联线。点击某条关联线则视为激活。</p>
|
||||
<h3>clearActiveLine()</h3>
|
||||
<p>清除当前激活的关联线的激活状态。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## 0.4.5
|
||||
|
||||
新增:1.支持关联线。 2.按住根节点也可以拖动画布。3.按住ctrl键可以调整多选节点。
|
||||
|
||||
## 0.4.4
|
||||
|
||||
新增:支持响应鼠标的横向滚动。
|
||||
|
||||
## 0.4.3
|
||||
|
||||
修复:前进回退后没有触发`data_change`事件的问题。
|
||||
|
||||
新增:支持自定义鼠标滚轮事件;鼠标滚轮调整为支持缩放视图和上下移动视图。
|
||||
|
||||
## 0.4.2
|
||||
|
||||
新增:`Node`类的`setText`方法增加第二个参数,以支持设置富文本内容。
|
||||
|
||||
## 0.4.1
|
||||
|
||||
新增:1.新增抛出节点鼠标移入和移除事件;2.节点富文本支持设置背景颜色;3.节点富文本支持清除样式。
|
||||
|
||||
修复:1.Mac系统触控板缩放相反的问题;2.设备window.devicePixelRatio不为1时,当存在富文本节点时导出的图片中富文本节点尺寸会变大的问题。
|
||||
|
||||
## 0.4.0
|
||||
|
||||
新增:节点支持富文本编辑。
|
||||
|
||||
## 0.3.4
|
||||
|
||||
新增:节点文本增加自动换行功能。
|
||||
|
||||
修复:1.修复批量删除的节点中如果存在根节点会出现删除异常的问题。2.修复底边风格的情况下,节点高度过高会和其他节点重叠的问题。
|
||||
|
||||
## 0.3.3
|
||||
|
||||
修复:根节点文字无法换行的问题。
|
||||
|
||||
## 0.3.2
|
||||
|
||||
修复:1.修复二级节点拖拽到其他节点或其他节点拖拽到二级节点时节点样式没有更新的问题;2.修复当思维导图实际内容大于屏幕宽高时,导出的时候超出的部分没有绘制水印的问题。
|
||||
|
||||
## 0.3.1
|
||||
|
||||
修复:1.删除背景图片不生效的问题;2.节点拖拽到根节点时连接线跑到根节点上方的问题。
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.4.5</h2>
|
||||
<p>新增:1.支持关联线。 2.按住根节点也可以拖动画布。3.按住ctrl键可以调整多选节点。</p>
|
||||
<h2>0.4.4</h2>
|
||||
<p>新增:支持响应鼠标的横向滚动。</p>
|
||||
<h2>0.4.3</h2>
|
||||
<p>修复:前进回退后没有触发<code>data_change</code>事件的问题。</p>
|
||||
<p>新增:支持自定义鼠标滚轮事件;鼠标滚轮调整为支持缩放视图和上下移动视图。</p>
|
||||
<h2>0.4.2</h2>
|
||||
<p>新增:<code>Node</code>类的<code>setText</code>方法增加第二个参数,以支持设置富文本内容。</p>
|
||||
<h2>0.4.1</h2>
|
||||
<p>新增:1.新增抛出节点鼠标移入和移除事件;2.节点富文本支持设置背景颜色;3.节点富文本支持清除样式。</p>
|
||||
<p>修复:1.Mac系统触控板缩放相反的问题;2.设备window.devicePixelRatio不为1时,当存在富文本节点时导出的图片中富文本节点尺寸会变大的问题。</p>
|
||||
<h2>0.4.0</h2>
|
||||
<p>新增:节点支持富文本编辑。</p>
|
||||
<h2>0.3.4</h2>
|
||||
<p>新增:节点文本增加自动换行功能。</p>
|
||||
<p>修复:1.修复批量删除的节点中如果存在根节点会出现删除异常的问题。2.修复底边风格的情况下,节点高度过高会和其他节点重叠的问题。</p>
|
||||
<h2>0.3.3</h2>
|
||||
<p>修复:根节点文字无法换行的问题。</p>
|
||||
<h2>0.3.2</h2>
|
||||
<p>修复:1.修复二级节点拖拽到其他节点或其他节点拖拽到二级节点时节点样式没有更新的问题;2.修复当思维导图实际内容大于屏幕宽高时,导出的时候超出的部分没有绘制水印的问题。</p>
|
||||
<h2>0.3.1</h2>
|
||||
<p>修复:1.删除背景图片不生效的问题;2.节点拖拽到根节点时连接线跑到根节点上方的问题。</p>
|
||||
<p>新增:背景图片展示增加位置和大小设置。导出的图片也同步支持该设置。</p>
|
||||
|
||||
@@ -40,6 +40,10 @@ const mindMap = new MindMap({
|
||||
| readonly(v0.1.7+) | Boolean | false | 是否是只读模式 | |
|
||||
| enableFreeDrag(v0.2.4+) | Boolean | false | 是否开启节点自由拖拽 | |
|
||||
| watermarkConfig(v0.2.4+) | Object | | 水印配置,详细配置请参考下方表格【水印配置】 | |
|
||||
| textAutoWrapWidth(v0.3.4+) | Number | 500 | 节点内每行文本达到该宽度后自动换行 | |
|
||||
| customHandleMousewheel(v0.4.3+) | Function | null | 自定义鼠标滚轮事件处理,可以传一个函数,回调参数为事件对象 | |
|
||||
| mousewheelAction(v0.4.3+) | String | zoom | 鼠标滚轮的行为,`zoom`(放大缩小)、`move`(上下移动)。如果`customHandleMousewheel`传了自定义函数,这个属性不生效 | |
|
||||
| mousewheelMoveStep(v0.4.3+) | Number | 100 | 当`mousewheelAction`设为`move`时,可以通过该属性控制鼠标滚动一下视图移动的步长,单位`px` | |
|
||||
|
||||
### 水印配置
|
||||
|
||||
@@ -83,14 +87,23 @@ mindMap.setTheme('主题名称')
|
||||
|
||||
主题的所有配置可以参考[默认主题](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js)。`defineTheme`方法会把你传入的配置和默认配置做合并。大部分主题其实需要自定义的部分不是很多,一个典型的自定义主题配置可以参考[blueSky](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js)。
|
||||
|
||||
### usePlugin(plugin)
|
||||
### usePlugin(plugin, opt = {})
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
- `opt`:v0.4.0+,插件参数。如果某个插件支持自定义选项的话可以通过这个参数传入。
|
||||
|
||||
|
||||
注册插件,如果需要使用非核心的一些功能,比如小地图、水印等,可以通过该方法进行注册。可链式调用。
|
||||
|
||||
注意:插件需要在实例化`MindMap`前注册。
|
||||
|
||||
### hasPlugin(plugin)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
获取是否注册了某个插件,返回的是插件在注册插件列表里的索引,为`-1`则代表插件没有注册。
|
||||
|
||||
## 静态属性
|
||||
|
||||
### pluginList
|
||||
@@ -119,11 +132,15 @@ mindMap.setTheme('主题名称')
|
||||
}
|
||||
```
|
||||
|
||||
### render()
|
||||
### render(callback)
|
||||
|
||||
- `callback`:`v0.3.2+`,`Function`,当重新渲染完成时调用
|
||||
|
||||
触发整体渲染,会进行节点复用,性能较`reRender`会更好一点,如果只是节点位置变化了可以调用该方法进行渲染
|
||||
|
||||
### reRender()
|
||||
### reRender(callback)
|
||||
|
||||
- `callback`:`v0.3.2+`,`Function`,当重新渲染完成时调用
|
||||
|
||||
整体重新渲染,会清空画布,节点也会重新创建,性能不好,慎重使用
|
||||
|
||||
@@ -161,6 +178,8 @@ mindMap.setTheme('主题名称')
|
||||
| node_mouseup | 节点的鼠标松开事件 | this(节点实例)、e(事件对象) |
|
||||
| node_dblclick | 节点的双击事件 | this(节点实例)、e(事件对象) |
|
||||
| node_contextmenu | 节点的右键菜单事件 | e(事件对象)、this(节点实例) |
|
||||
| node_mouseenter(v0.4.1+) | 节点的鼠标移入事件 | this(节点实例)、e(事件对象) |
|
||||
| node_mouseleave(v0.4.1+) | 节点的鼠标移出事件 | this(节点实例)、e(事件对象) |
|
||||
| before_node_active | 节点激活前事件 | this(节点实例)、activeNodeList(当前激活的所有节点列表) |
|
||||
| node_active | 节点激活事件 | this(节点实例)、activeNodeList(当前激活的所有节点列表) |
|
||||
| expand_btn_click | 节点展开或收缩事件 | this(节点实例) |
|
||||
@@ -169,6 +188,11 @@ mindMap.setTheme('主题名称')
|
||||
| scale | 放大缩小事件 | scale(缩放比例) |
|
||||
| node_img_dblclick(v0.2.15+) | 节点内图片的双击事件 | this(节点实例)、e(事件对象) |
|
||||
| node_tree_render_end(v0.2.16+) | 节点树渲染完毕事件 | |
|
||||
| rich_text_selection_change(v0.4.0+) | 当注册了`RichText`插件时可用。当节点编辑时,文本选区发生改变时触发 | hasRange(是否存在选区)、rectInfo(选区的尺寸和位置信息)、formatInfo(选区的文本格式化信息) |
|
||||
| transforming-dom-to-images(v0.4.0+) | 当注册了`RichText`插件时可用。当`svg`中存在`DOM`节点时,导出为图片时会将`DOM`节点转换为图片,转换过程中会触发该事件,可用通过该事件给用户提示,告知目前转换到的节点 | index(当前转换到的节点索引)、len(一共需要转换的节点数量) |
|
||||
| node_dragging(v0.4.5+) | 当某个节点被拖拽时触发 | node(当前被拖拽的节点) |
|
||||
| node_dragend(v0.4.5+) | 节点被拖拽结束时触发 | |
|
||||
| associative_line_click(v0.4.5+) | 点击某条关联线时触发 | path(连接线节点)、clickPath(不可见的点击线节点)、node(起始节点)、toNode(目标节点) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
@@ -234,40 +258,40 @@ mindMap.updateConfig({
|
||||
|
||||
执行命令,每执行一个命令就会在历史堆栈里添加一条记录用于回退或前进。所有命令如下:
|
||||
|
||||
| 命令名称 | 描述 | 参数 |
|
||||
| --------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| SELECT_ALL | 全选 | |
|
||||
| BACK | 回退指定的步数 | step(要回退的步数,默认为1) |
|
||||
| FORWARD | 前进指定的步数 | step(要前进的步数,默认为1) |
|
||||
| INSERT_NODE | 插入同级节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效 | |
|
||||
| INSERT_CHILD_NODE | 插入子节点,操作节点为当前激活的节点 | |
|
||||
| UP_NODE | 上移节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的第一个节点使用无效 | |
|
||||
| DOWN_NODE | 操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的最后一个节点使用无效 | |
|
||||
| REMOVE_NODE | 删除节点,操作节点为当前激活的节点 | |
|
||||
| PASTE_NODE | 粘贴节点到节点,操作节点为当前激活的节点 | data(要粘贴的节点数据,一般通过`renderer.copyNode()`方法和`renderer.cutNode()`方法获取) |
|
||||
| CUT_NODE | 剪切节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点使用无效 | callback(回调函数,剪切的节点数据会通过调用该函数并通过参数返回) |
|
||||
| SET_NODE_STYLE | 修改节点样式 | node(要设置样式的节点)、prop(样式属性)、value(样式属性值)、isActive(布尔值,是否设置的是激活状态的样式) |
|
||||
| SET_NODE_ACTIVE | 设置节点是否激活 | node(要设置的节点)、active(布尔值,是否激活) |
|
||||
| CLEAR_ACTIVE_NODE | 清除当前已激活节点的激活状态,操作节点为当前激活的节点 | |
|
||||
| SET_NODE_EXPAND | 设置节点是否展开 | node(要设置的节点)、expand(布尔值,是否展开) |
|
||||
| EXPAND_ALL | 展开所有节点 | |
|
||||
| UNEXPAND_ALL | 收起所有节点 | |
|
||||
| UNEXPAND_TO_LEVEL(v0.2.8+) | 展开到指定层级 | level(要展开到的层级,1、2、3...) |
|
||||
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据 | node(要设置的节点)、data(对象,要更新的数据,如`{expand: true}`) |
|
||||
| SET_NODE_TEXT | 设置节点文本 | node(要设置的节点)、text(要设置的文本字符串,换行可以使用`\n`) |
|
||||
| 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_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)里获取到) |
|
||||
| INSERT_AFTER(v0.1.5+) | 将节点移动到另一个节点的后面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| INSERT_BEFORE(v0.1.5+) | 将节点移动到另一个节点的前面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| MOVE_NODE_TO(v0.1.5+) | 移动一个节点作为另一个节点的子节点 | node(要移动的节点)、 toNode(目标节点) |
|
||||
| ADD_GENERALIZATION(v0.2.0+) | 添加节点概要 | data(概要的数据,对象格式,节点的数字段都支持,默认为{text: '概要'}) |
|
||||
| REMOVE_GENERALIZATION(v0.2.0+) | 删除节点概要 | |
|
||||
| SET_NODE_CUSTOM_POSITION(v0.2.0+) | 设置节点自定义位置 | node(要设置的节点)、 left(自定义的x坐标,默认为undefined)、 top(自定义的y坐标,默认为undefined) |
|
||||
| RESET_LAYOUT(v0.2.0+) | 一键整理布局 | |
|
||||
| SET_NODE_SHAPE(v0.2.4+) | 设置节点形状 | node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
||||
| 命令名称 | 描述 | 参数 |
|
||||
| ----------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| SELECT_ALL | 全选 | |
|
||||
| BACK | 回退指定的步数 | step(要回退的步数,默认为1) |
|
||||
| FORWARD | 前进指定的步数 | step(要前进的步数,默认为1) |
|
||||
| INSERT_NODE | 插入同级节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效 | |
|
||||
| INSERT_CHILD_NODE | 插入子节点,操作节点为当前激活的节点 | |
|
||||
| UP_NODE | 上移节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的第一个节点使用无效 | |
|
||||
| DOWN_NODE | 操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的最后一个节点使用无效 | |
|
||||
| REMOVE_NODE | 删除节点,操作节点为当前激活的节点 | |
|
||||
| PASTE_NODE | 粘贴节点到节点,操作节点为当前激活的节点 | data(要粘贴的节点数据,一般通过`renderer.copyNode()`方法和`renderer.cutNode()`方法获取) |
|
||||
| CUT_NODE | 剪切节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点使用无效 | callback(回调函数,剪切的节点数据会通过调用该函数并通过参数返回) |
|
||||
| SET_NODE_STYLE | 修改节点样式 | node(要设置样式的节点)、prop(样式属性)、value(样式属性值)、isActive(布尔值,是否设置的是激活状态的样式) |
|
||||
| SET_NODE_ACTIVE | 设置节点是否激活 | node(要设置的节点)、active(布尔值,是否激活) |
|
||||
| CLEAR_ACTIVE_NODE | 清除当前已激活节点的激活状态,操作节点为当前激活的节点 | |
|
||||
| SET_NODE_EXPAND | 设置节点是否展开 | node(要设置的节点)、expand(布尔值,是否展开) |
|
||||
| EXPAND_ALL | 展开所有节点 | |
|
||||
| UNEXPAND_ALL | 收起所有节点 | |
|
||||
| UNEXPAND_TO_LEVEL(v0.2.8+) | 展开到指定层级 | level(要展开到的层级,1、2、3...) |
|
||||
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据 | node(要设置的节点)、data(对象,要更新的数据,如`{expand: true}`) |
|
||||
| SET_NODE_TEXT | 设置节点文本 | node(要设置的节点)、text(要设置的文本字符串,换行可以使用`\n`)、richText(v0.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_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)里获取到) |
|
||||
| INSERT_AFTER(v0.1.5+) | 将节点移动到另一个节点的后面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| INSERT_BEFORE(v0.1.5+) | 将节点移动到另一个节点的前面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| MOVE_NODE_TO(v0.1.5+) | 移动一个节点作为另一个节点的子节点 | node(要移动的节点)、 toNode(目标节点) |
|
||||
| ADD_GENERALIZATION(v0.2.0+) | 添加节点概要 | data(概要的数据,对象格式,节点的数字段都支持,默认为{text: '概要'}) |
|
||||
| REMOVE_GENERALIZATION(v0.2.0+) | 删除节点概要 | |
|
||||
| SET_NODE_CUSTOM_POSITION(v0.2.0+) | 设置节点自定义位置 | node(要设置的节点)、 left(自定义的x坐标,默认为undefined)、 top(自定义的y坐标,默认为undefined) |
|
||||
| RESET_LAYOUT(v0.2.0+) | 一键整理布局 | |
|
||||
| SET_NODE_SHAPE(v0.2.4+) | 设置节点形状 | node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
||||
|
||||
### setData(data)
|
||||
|
||||
@@ -307,4 +331,16 @@ mindMap.updateConfig({
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
将浏览器可视窗口的坐标转换成相对于画布的坐标
|
||||
将浏览器可视窗口的坐标转换成相对于画布的坐标
|
||||
|
||||
### addPlugin(plugin, opt)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
注册插件,使用`MindMap.usePlugin`注册插件只能在实例化之前,实例化后注册的插件是不会生效的,所以如果想在实例化后注册插件可以使用实例的`addPlugin`方法。
|
||||
|
||||
### removePlugin(plugin)
|
||||
|
||||
> v0.4.0+
|
||||
|
||||
移除注册的插件,无论是通过`usePlugin`还是`addPlugin`方法注册的插件都可以移除。
|
||||
@@ -140,6 +140,34 @@
|
||||
<td>水印配置,详细配置请参考下方表格【水印配置】</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textAutoWrapWidth(v0.3.4+)</td>
|
||||
<td>Number</td>
|
||||
<td>500</td>
|
||||
<td>节点内每行文本达到该宽度后自动换行</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customHandleMousewheel(v0.4.3+)</td>
|
||||
<td>Function</td>
|
||||
<td>null</td>
|
||||
<td>自定义鼠标滚轮事件处理,可以传一个函数,回调参数为事件对象</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheelAction(v0.4.3+)</td>
|
||||
<td>String</td>
|
||||
<td>zoom</td>
|
||||
<td>鼠标滚轮的行为,<code>zoom</code>(放大缩小)、<code>move</code>(上下移动)。如果<code>customHandleMousewheel</code>传了自定义函数,这个属性不生效</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheelMoveStep(v0.4.3+)</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>当<code>mousewheelAction</code>设为<code>move</code>时,可以通过该属性控制鼠标滚动一下视图移动的步长,单位<code>px</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>水印配置</h3>
|
||||
@@ -207,12 +235,20 @@ MindMap.defineTheme(<span class="hljs-string">'主题名称'</span>, {
|
||||
mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
</code></pre>
|
||||
<p>主题的所有配置可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">默认主题</a>。<code>defineTheme</code>方法会把你传入的配置和默认配置做合并。大部分主题其实需要自定义的部分不是很多,一个典型的自定义主题配置可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js">blueSky</a>。</p>
|
||||
<h3>usePlugin(plugin)</h3>
|
||||
<h3>usePlugin(plugin, opt = {})</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>opt</code>:v0.4.0+,插件参数。如果某个插件支持自定义选项的话可以通过这个参数传入。</li>
|
||||
</ul>
|
||||
<p>注册插件,如果需要使用非核心的一些功能,比如小地图、水印等,可以通过该方法进行注册。可链式调用。</p>
|
||||
<p>注意:插件需要在实例化<code>MindMap</code>前注册。</p>
|
||||
<h3>hasPlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>获取是否注册了某个插件,返回的是插件在注册插件列表里的索引,为<code>-1</code>则代表插件没有注册。</p>
|
||||
<h2>静态属性</h2>
|
||||
<h3>pluginList</h3>
|
||||
<blockquote>
|
||||
@@ -235,9 +271,15 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
scaleY, <span class="hljs-comment">// Number,思维导图图形的垂直缩放值</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>render()</h3>
|
||||
<h3>render(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>:<code>v0.3.2+</code>,<code>Function</code>,当重新渲染完成时调用</li>
|
||||
</ul>
|
||||
<p>触发整体渲染,会进行节点复用,性能较<code>reRender</code>会更好一点,如果只是节点位置变化了可以调用该方法进行渲染</p>
|
||||
<h3>reRender()</h3>
|
||||
<h3>reRender(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>:<code>v0.3.2+</code>,<code>Function</code>,当重新渲染完成时调用</li>
|
||||
</ul>
|
||||
<p>整体重新渲染,会清空画布,节点也会重新创建,性能不好,慎重使用</p>
|
||||
<h3>resize()</h3>
|
||||
<p>容器尺寸变化后,需要调用该方法进行适应</p>
|
||||
@@ -339,6 +381,16 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<td>e(事件对象)、this(节点实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseenter(v0.4.1+)</td>
|
||||
<td>节点的鼠标移入事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseleave(v0.4.1+)</td>
|
||||
<td>节点的鼠标移出事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_node_active</td>
|
||||
<td>节点激活前事件</td>
|
||||
<td>this(节点实例)、activeNodeList(当前激活的所有节点列表)</td>
|
||||
@@ -378,6 +430,31 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<td>节点树渲染完毕事件</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rich_text_selection_change(v0.4.0+)</td>
|
||||
<td>当注册了<code>RichText</code>插件时可用。当节点编辑时,文本选区发生改变时触发</td>
|
||||
<td>hasRange(是否存在选区)、rectInfo(选区的尺寸和位置信息)、formatInfo(选区的文本格式化信息)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>transforming-dom-to-images(v0.4.0+)</td>
|
||||
<td>当注册了<code>RichText</code>插件时可用。当<code>svg</code>中存在<code>DOM</code>节点时,导出为图片时会将<code>DOM</code>节点转换为图片,转换过程中会触发该事件,可用通过该事件给用户提示,告知目前转换到的节点</td>
|
||||
<td>index(当前转换到的节点索引)、len(一共需要转换的节点数量)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dragging(v0.4.5+)</td>
|
||||
<td>当某个节点被拖拽时触发</td>
|
||||
<td>node(当前被拖拽的节点)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dragend(v0.4.5+)</td>
|
||||
<td>节点被拖拽结束时触发</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>associative_line_click(v0.4.5+)</td>
|
||||
<td>点击某条关联线时触发</td>
|
||||
<td>path(连接线节点)、clickPath(不可见的点击线节点)、node(起始节点)、toNode(目标节点)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
@@ -519,7 +596,7 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<tr>
|
||||
<td>SET_NODE_TEXT</td>
|
||||
<td>设置节点文本</td>
|
||||
<td>node(要设置的节点)、text(要设置的文本字符串,换行可以使用<code>\n</code>)</td>
|
||||
<td>node(要设置的节点)、text(要设置的文本字符串,换行可以使用<code>\n</code>)、richText(v0.4.0+,如果要设置的是富文本字符,需要设为<code>true</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_IMAGE</td>
|
||||
@@ -616,6 +693,16 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>将浏览器可视窗口的坐标转换成相对于画布的坐标</p>
|
||||
<h3>addPlugin(plugin, opt)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>注册插件,使用<code>MindMap.usePlugin</code>注册插件只能在实例化之前,实例化后注册的插件是不会生效的,所以如果想在实例化后注册插件可以使用实例的<code>addPlugin</code>方法。</p>
|
||||
<h3>removePlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.4.0+</p>
|
||||
</blockquote>
|
||||
<p>移除注册的插件,无论是通过<code>usePlugin</code>还是<code>addPlugin</code>方法注册的插件都可以移除。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,18 +19,39 @@ MindMap.usePlugin(Export)
|
||||
|
||||
导出为`png`,异步方法,返回图片数据,`data:url`数据,可以自行下载或显示
|
||||
|
||||
### svg()
|
||||
### svg(name, domToImage = false, plusCssText)
|
||||
|
||||
- `name`:`svg`标题
|
||||
|
||||
- `domToImage`:v0.4.0+,当开启了节点富文本编辑,可以通过该参数指定是否将`svg`中的`dom`节点转换成图片的形式
|
||||
|
||||
- `plusCssText`:v0.4.0+,当开启了节点富文本编辑,且`domToImage`传了`false`时,可以添加附加的`css`样式,如果`svg`中存在`dom`节点,想要设置一些针对节点的样式可以通过这个参数传入,比如:
|
||||
|
||||
```js
|
||||
svg(
|
||||
'',
|
||||
false,
|
||||
`* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}`
|
||||
)
|
||||
```
|
||||
|
||||
导出为`svg`,异步方法,返回`svg`数据,`data:url`数据,可以自行下载或显示
|
||||
|
||||
### getSvgData()
|
||||
### getSvgData(domToImage)
|
||||
|
||||
- `domToImage`:v0.4.0+,如果开启了节点富文本,则可以通过该参数指定是否要将`svg`中嵌入的`DOM`节点转换为图片。
|
||||
|
||||
获取`svg`数据,异步方法,返回一个对象:
|
||||
|
||||
```js
|
||||
{
|
||||
node// svg对象
|
||||
str// svg字符串
|
||||
str// svg字符串,如果开启了富文本编辑且domToImage设为true,那么该值返回的svg字符内的dom节点会被转换成图片的形式
|
||||
nodeWithDomToImg// v0.4.0+,DOM节点转换为图片后的svg对象,只有当开启了富文本编辑且domToImage设为true才有值,否则为null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -12,13 +12,38 @@ MindMap.usePlugin(Export)
|
||||
<h2>方法</h2>
|
||||
<h3>png()</h3>
|
||||
<p>导出为<code>png</code>,异步方法,返回图片数据,<code>data:url</code>数据,可以自行下载或显示</p>
|
||||
<h3>svg()</h3>
|
||||
<h3>svg(name, domToImage = false, plusCssText)</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>name</code>:<code>svg</code>标题</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>domToImage</code>:v0.4.0+,当开启了节点富文本编辑,可以通过该参数指定是否将<code>svg</code>中的<code>dom</code>节点转换成图片的形式</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>plusCssText</code>:v0.4.0+,当开启了节点富文本编辑,且<code>domToImage</code>传了<code>false</code>时,可以添加附加的<code>css</code>样式,如果<code>svg</code>中存在<code>dom</code>节点,想要设置一些针对节点的样式可以通过这个参数传入,比如:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>svg(
|
||||
<span class="hljs-string">''</span>,
|
||||
<span class="hljs-literal">false</span>,
|
||||
<span class="hljs-string">`* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}`</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>导出为<code>svg</code>,异步方法,返回<code>svg</code>数据,<code>data:url</code>数据,可以自行下载或显示</p>
|
||||
<h3>getSvgData()</h3>
|
||||
<h3>getSvgData(domToImage)</h3>
|
||||
<ul>
|
||||
<li><code>domToImage</code>:v0.4.0+,如果开启了节点富文本,则可以通过该参数指定是否要将<code>svg</code>中嵌入的<code>DOM</code>节点转换为图片。</li>
|
||||
</ul>
|
||||
<p>获取<code>svg</code>数据,异步方法,返回一个对象:</p>
|
||||
<pre class="hljs"><code>{
|
||||
node<span class="hljs-comment">// svg对象</span>
|
||||
str<span class="hljs-comment">// svg字符串</span>
|
||||
str<span class="hljs-comment">// svg字符串,如果开启了富文本编辑且domToImage设为true,那么该值返回的svg字符内的dom节点会被转换成图片的形式</span>
|
||||
nodeWithDomToImg<span class="hljs-comment">// v0.4.0+,DOM节点转换为图片后的svg对象,只有当开启了富文本编辑且domToImage设为true才有值,否则为null</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>pdf(name)</h3>
|
||||
|
||||