mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-24 18:38:26 +08:00
Compare commits
23 Commits
0.7.2
...
0.7.3-fix.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c4e72eb29 | ||
|
|
88e3c1f660 | ||
|
|
e6c92d4a5e | ||
|
|
745531f20f | ||
|
|
3acd425c09 | ||
|
|
8dcc7c985d | ||
|
|
253ded33bf | ||
|
|
2c6b8294f4 | ||
|
|
83a5ef8e2e | ||
|
|
b959e90723 | ||
|
|
89ebc9a1fa | ||
|
|
56d2e34fbd | ||
|
|
0f2aed7e8a | ||
|
|
288ceafa92 | ||
|
|
99dc443142 | ||
|
|
b6440eba1a | ||
|
|
545e46babc | ||
|
|
b95b6af1b1 | ||
|
|
ccef5fc581 | ||
|
|
ed82fe5a61 | ||
|
|
1550f032d9 | ||
|
|
7d2758a21c | ||
|
|
1beb03eaa6 |
17
README.md
17
README.md
@@ -39,6 +39,7 @@ Github:[releases](https://github.com/wanglin2/mind-map/releases)。
|
||||
- [x] 支持导出为`json`、`png`、`svg`、`pdf`、`markdown`、`xmind`,支持从`json`、`xmind`、`markdown`导入
|
||||
- [x] 支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条
|
||||
- [x] 提供丰富的配置,满足各种场景各种使用习惯
|
||||
- [x] 支持协同编辑
|
||||
|
||||
# 安装
|
||||
|
||||
@@ -93,11 +94,11 @@ const mindMap = new MindMap({
|
||||
|
||||
# 请作者喝杯咖啡
|
||||
|
||||
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡哟~
|
||||
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~
|
||||
|
||||
> 厚椰乳一盒 + 纯牛奶半盒 + 冰块 + 咖啡液 = 生椰拿铁 yyds
|
||||
|
||||
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。你的头像和名字将会出现在下面和[文档页面](https://wanglin2.github.io/mind-map/#/doc/zh/introduction/%E8%AF%B7%E4%BD%9C%E8%80%85%E5%96%9D%E6%9D%AF%E5%92%96%E5%95%A1)
|
||||
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。
|
||||
|
||||
<p>
|
||||
<img src="./web/src/assets/img/alipay.jpg" style="width: 300px" />
|
||||
@@ -189,4 +190,16 @@ const mindMap = new MindMap({
|
||||
<img src="./web/src/assets/avatar/沐风牧草.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>沐风牧草</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/有希.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>有希</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/樊笼.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>樊笼</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/达仁科技.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>达仁科技</span>
|
||||
</span>
|
||||
</p>
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><link rel="icon" href="dist/logo.ico"><title>思绪思维导图</title><script>// 自定义静态资源的路径
|
||||
window.externalPublicPath = './dist/'
|
||||
// 接管应用
|
||||
window.takeOverApp = false</script><link href="dist/css/chunk-vendors.css?009f4c7305e0f9f13b31" rel="stylesheet"><link href="dist/css/app.css?009f4c7305e0f9f13b31" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
window.takeOverApp = false</script><link href="dist/css/chunk-vendors.css?97b4d7ae279db040269e" rel="stylesheet"><link href="dist/css/app.css?97b4d7ae279db040269e" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
@@ -66,4 +66,4 @@
|
||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||
// 实例化页面
|
||||
window.initApp()
|
||||
}</script><script src="dist/js/chunk-vendors.js?009f4c7305e0f9f13b31"></script><script src="dist/js/app.js?009f4c7305e0f9f13b31"></script></body></html>
|
||||
}</script><script src="dist/js/chunk-vendors.js?97b4d7ae279db040269e"></script><script src="dist/js/app.js?97b4d7ae279db040269e"></script></body></html>
|
||||
152
simple-mind-map/bin/wsServer.mjs
Normal file
152
simple-mind-map/bin/wsServer.mjs
Normal file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import ws from 'ws'
|
||||
import http from 'http'
|
||||
import * as map from 'lib0/map'
|
||||
|
||||
const wsReadyStateConnecting = 0
|
||||
const wsReadyStateOpen = 1
|
||||
const wsReadyStateClosing = 2 // eslint-disable-line
|
||||
const wsReadyStateClosed = 3 // eslint-disable-line
|
||||
|
||||
const pingTimeout = 30000
|
||||
|
||||
const port = process.env.PORT || 4444
|
||||
// @ts-ignore
|
||||
const wss = new ws.Server({ noServer: true })
|
||||
|
||||
const server = http.createServer((request, response) => {
|
||||
response.writeHead(200, { 'Content-Type': 'text/plain' })
|
||||
response.end('okay')
|
||||
})
|
||||
|
||||
/**
|
||||
* Map froms topic-name to set of subscribed clients.
|
||||
* @type {Map<string, Set<any>>}
|
||||
*/
|
||||
const topics = new Map()
|
||||
|
||||
/**
|
||||
* @param {any} conn
|
||||
* @param {object} message
|
||||
*/
|
||||
const send = (conn, message) => {
|
||||
if (
|
||||
conn.readyState !== wsReadyStateConnecting &&
|
||||
conn.readyState !== wsReadyStateOpen
|
||||
) {
|
||||
conn.close()
|
||||
}
|
||||
try {
|
||||
conn.send(JSON.stringify(message))
|
||||
} catch (e) {
|
||||
conn.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a new client
|
||||
* @param {any} conn
|
||||
*/
|
||||
const onconnection = conn => {
|
||||
/**
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
const subscribedTopics = new Set()
|
||||
let closed = false
|
||||
// Check if connection is still alive
|
||||
let pongReceived = true
|
||||
const pingInterval = setInterval(() => {
|
||||
if (!pongReceived) {
|
||||
conn.close()
|
||||
clearInterval(pingInterval)
|
||||
} else {
|
||||
pongReceived = false
|
||||
try {
|
||||
conn.ping()
|
||||
} catch (e) {
|
||||
conn.close()
|
||||
}
|
||||
}
|
||||
}, pingTimeout)
|
||||
conn.on('pong', () => {
|
||||
pongReceived = true
|
||||
})
|
||||
conn.on('close', () => {
|
||||
subscribedTopics.forEach(topicName => {
|
||||
const subs = topics.get(topicName) || new Set()
|
||||
subs.delete(conn)
|
||||
if (subs.size === 0) {
|
||||
topics.delete(topicName)
|
||||
}
|
||||
})
|
||||
subscribedTopics.clear()
|
||||
closed = true
|
||||
})
|
||||
conn.on(
|
||||
'message',
|
||||
/** @param {object} message */ message => {
|
||||
if (typeof message === 'string') {
|
||||
message = JSON.parse(message)
|
||||
}
|
||||
if (message && message.type && !closed) {
|
||||
switch (message.type) {
|
||||
case 'subscribe':
|
||||
/** @type {Array<string>} */ ;(message.topics || []).forEach(
|
||||
topicName => {
|
||||
if (typeof topicName === 'string') {
|
||||
// add conn to topic
|
||||
const topic = map.setIfUndefined(
|
||||
topics,
|
||||
topicName,
|
||||
() => new Set()
|
||||
)
|
||||
topic.add(conn)
|
||||
// add topic to conn
|
||||
subscribedTopics.add(topicName)
|
||||
}
|
||||
}
|
||||
)
|
||||
break
|
||||
case 'unsubscribe':
|
||||
/** @type {Array<string>} */ ;(message.topics || []).forEach(
|
||||
topicName => {
|
||||
const subs = topics.get(topicName)
|
||||
if (subs) {
|
||||
subs.delete(conn)
|
||||
}
|
||||
}
|
||||
)
|
||||
break
|
||||
case 'publish':
|
||||
if (message.topic) {
|
||||
const receivers = topics.get(message.topic)
|
||||
if (receivers) {
|
||||
message.clients = receivers.size
|
||||
receivers.forEach(receiver => send(receiver, message))
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'ping':
|
||||
send(conn, { type: 'pong' })
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
wss.on('connection', onconnection)
|
||||
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
// You may check auth of request here..
|
||||
/**
|
||||
* @param {any} ws
|
||||
*/
|
||||
const handleAuth = ws => {
|
||||
wss.emit('connection', ws, request)
|
||||
}
|
||||
wss.handleUpgrade(request, socket, head, handleAuth)
|
||||
})
|
||||
|
||||
server.listen(port)
|
||||
|
||||
console.log('Signaling server running on localhost:', port)
|
||||
@@ -258,15 +258,13 @@ class MindMap {
|
||||
|
||||
// 动态设置思维导图数据,纯节点数据
|
||||
setData(data) {
|
||||
data = simpleDeepClone(data || {})
|
||||
this.execCommand('CLEAR_ACTIVE_NODE')
|
||||
this.command.clearHistory()
|
||||
this.command.addHistory()
|
||||
if (this.richText) {
|
||||
this.renderer.renderTree = this.richText.handleSetData(data)
|
||||
} else {
|
||||
this.renderer.renderTree = data
|
||||
}
|
||||
this.renderer.setData(data)
|
||||
this.reRender(() => {}, CONSTANTS.SET_DATA)
|
||||
this.emit('set_data', data)
|
||||
}
|
||||
|
||||
// 动态设置思维导图数据,包括节点数据、布局、主题、视图
|
||||
|
||||
346
simple-mind-map/package-lock.json
generated
346
simple-mind-map/package-lock.json
generated
@@ -18,7 +18,9 @@
|
||||
"quill": "^1.3.6",
|
||||
"tern": "^0.24.3",
|
||||
"uuid": "^9.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
"xml-js": "^1.6.11",
|
||||
"y-webrtc": "^10.2.5",
|
||||
"yjs": "^13.6.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.25.0",
|
||||
@@ -290,6 +292,25 @@
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -310,6 +331,29 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
@@ -574,6 +618,11 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/err-code": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz",
|
||||
"integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA=="
|
||||
},
|
||||
"node_modules/errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
@@ -873,6 +922,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-browser-rtc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz",
|
||||
"integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ=="
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
|
||||
@@ -1012,6 +1066,25 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
@@ -1150,6 +1223,15 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/isomorphic.js": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
|
||||
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
}
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
|
||||
@@ -1248,6 +1330,25 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lib0": {
|
||||
"version": "0.2.86",
|
||||
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.86.tgz",
|
||||
"integrity": "sha512-kxigQTM4Q7NwJkEgdqQvU21qiR37twcqqLmh+/SbiGbRLfPlLVbHyY9sWp7PwXh0Xus9ELDSjsUOwcrdt5yZ4w==",
|
||||
"dependencies": {
|
||||
"isomorphic.js": "^0.2.4"
|
||||
},
|
||||
"bin": {
|
||||
"0gentesthtml": "bin/gentesthtml.js",
|
||||
"0serve": "bin/0serve.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
}
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
@@ -1960,7 +2061,6 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -2016,6 +2116,14 @@
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@@ -2176,6 +2284,47 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-peer": {
|
||||
"version": "9.11.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz",
|
||||
"integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"debug": "^4.3.2",
|
||||
"err-code": "^3.0.1",
|
||||
"get-browser-rtc": "^1.1.0",
|
||||
"queue-microtask": "^1.2.3",
|
||||
"randombytes": "^2.1.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-peer/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/stackblur-canvas": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
|
||||
@@ -2410,6 +2559,27 @@
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml-js": {
|
||||
"version": "1.6.11",
|
||||
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||
@@ -2421,6 +2591,65 @@
|
||||
"xml-js": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/y-protocols": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz",
|
||||
"integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lib0": "^0.2.85"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"yjs": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y-webrtc": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.5.tgz",
|
||||
"integrity": "sha512-ZyBNvTI5L28sQ2PQI0T/JvyWgvuTq05L21vGkIlcvNLNSJqAaLCBJRe3FHEqXoaogqWmRcEAKGfII4ErNXMnNw==",
|
||||
"dependencies": {
|
||||
"lib0": "^0.2.42",
|
||||
"simple-peer": "^9.11.0",
|
||||
"y-protocols": "^1.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"y-webrtc-signaling": "bin/server.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"ws": "^7.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yjs": {
|
||||
"version": "13.6.8",
|
||||
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.8.tgz",
|
||||
"integrity": "sha512-ZPq0hpJQb6f59B++Ngg4cKexDJTvfOgeiv0sBc4sUm8CaBWH7OQC4kcCgrqbjJ/B2+6vO49exvTmYfdlPtcjbg==",
|
||||
"dependencies": {
|
||||
"lib0": "^0.2.74"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
@@ -2628,6 +2857,11 @@
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"optional": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -2642,6 +2876,15 @@
|
||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
|
||||
},
|
||||
"buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
@@ -2834,6 +3077,11 @@
|
||||
"tapable": "^0.2.3"
|
||||
}
|
||||
},
|
||||
"err-code": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz",
|
||||
"integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA=="
|
||||
},
|
||||
"errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
@@ -3066,6 +3314,11 @@
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
|
||||
},
|
||||
"get-browser-rtc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz",
|
||||
"integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
|
||||
@@ -3163,6 +3416,11 @@
|
||||
"text-segmentation": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
@@ -3262,6 +3520,11 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
},
|
||||
"isomorphic.js": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
|
||||
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw=="
|
||||
},
|
||||
"js-sdsl": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
|
||||
@@ -3338,6 +3601,14 @@
|
||||
"type-check": "~0.4.0"
|
||||
}
|
||||
},
|
||||
"lib0": {
|
||||
"version": "0.2.86",
|
||||
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.86.tgz",
|
||||
"integrity": "sha512-kxigQTM4Q7NwJkEgdqQvU21qiR37twcqqLmh+/SbiGbRLfPlLVbHyY9sWp7PwXh0Xus9ELDSjsUOwcrdt5yZ4w==",
|
||||
"requires": {
|
||||
"isomorphic.js": "^0.2.4"
|
||||
}
|
||||
},
|
||||
"lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
@@ -3765,8 +4036,7 @@
|
||||
"queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
|
||||
},
|
||||
"quill": {
|
||||
"version": "1.3.6",
|
||||
@@ -3807,6 +4077,14 @@
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@@ -3916,6 +4194,32 @@
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"simple-peer": {
|
||||
"version": "9.11.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz",
|
||||
"integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==",
|
||||
"requires": {
|
||||
"buffer": "^6.0.3",
|
||||
"debug": "^4.3.2",
|
||||
"err-code": "^3.0.1",
|
||||
"get-browser-rtc": "^1.1.0",
|
||||
"queue-microtask": "^1.2.3",
|
||||
"randombytes": "^2.1.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"stackblur-canvas": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
|
||||
@@ -4088,6 +4392,13 @@
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"optional": true,
|
||||
"requires": {}
|
||||
},
|
||||
"xml-js": {
|
||||
"version": "1.6.11",
|
||||
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||
@@ -4096,6 +4407,33 @@
|
||||
"sax": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"y-protocols": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz",
|
||||
"integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==",
|
||||
"requires": {
|
||||
"lib0": "^0.2.85"
|
||||
}
|
||||
},
|
||||
"y-webrtc": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.5.tgz",
|
||||
"integrity": "sha512-ZyBNvTI5L28sQ2PQI0T/JvyWgvuTq05L21vGkIlcvNLNSJqAaLCBJRe3FHEqXoaogqWmRcEAKGfII4ErNXMnNw==",
|
||||
"requires": {
|
||||
"lib0": "^0.2.42",
|
||||
"simple-peer": "^9.11.0",
|
||||
"ws": "^7.2.0",
|
||||
"y-protocols": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"yjs": {
|
||||
"version": "13.6.8",
|
||||
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.8.tgz",
|
||||
"integrity": "sha512-ZPq0hpJQb6f59B++Ngg4cKexDJTvfOgeiv0sBc4sUm8CaBWH7OQC4kcCgrqbjJ/B2+6vO49exvTmYfdlPtcjbg==",
|
||||
"requires": {
|
||||
"lib0": "^0.2.74"
|
||||
}
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.3-fix.2",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
@@ -22,7 +22,8 @@
|
||||
"scripts": {
|
||||
"lint": "eslint src/",
|
||||
"format": "prettier --write .",
|
||||
"types": "npx -p typescript tsc index.js --declaration --allowJs --emitDeclarationOnly --outDir types --target es2017"
|
||||
"types": "npx -p typescript tsc index.js --declaration --allowJs --emitDeclarationOnly --outDir types --target es2017",
|
||||
"wsServe": "node ./bin/wsServer.mjs"
|
||||
},
|
||||
"module": "index.js",
|
||||
"main": "./dist/simpleMindMap.umd.min.js",
|
||||
@@ -37,7 +38,9 @@
|
||||
"quill": "^1.3.6",
|
||||
"tern": "^0.24.3",
|
||||
"uuid": "^9.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
"xml-js": "^1.6.11",
|
||||
"y-webrtc": "^10.2.5",
|
||||
"yjs": "^13.6.8"
|
||||
},
|
||||
"keywords": [
|
||||
"javascript",
|
||||
|
||||
@@ -204,5 +204,10 @@ export const defaultOpt = {
|
||||
},
|
||||
// 自定义标签的颜色
|
||||
// {pass: 'green, unpass: 'red'}
|
||||
tagsColorMap: {}
|
||||
tagsColorMap: {},
|
||||
// 节点协作样式配置
|
||||
cooperateStyle: {
|
||||
avatarSize: 22,// 头像大小
|
||||
fontSize: 12,// 如果是文字头像,那么文字的大小
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,15 @@ class Render {
|
||||
)(this, this.mindMap.opt.layout)
|
||||
}
|
||||
|
||||
// 重新设置思维导图数据
|
||||
setData(data) {
|
||||
if (this.mindMap.richText) {
|
||||
this.renderTree = this.mindMap.richText.handleSetData(data)
|
||||
} else {
|
||||
this.renderTree = data
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
// 点击事件
|
||||
@@ -503,7 +512,7 @@ class Render {
|
||||
uid: createUid(),
|
||||
...(appointData || {})
|
||||
},
|
||||
children: [...createUidForAppointNodes(appointChildren)]
|
||||
children: [...createUidForAppointNodes(appointChildren, true)]
|
||||
}
|
||||
parent.nodeData.children.splice(index + 1, 0, newNodeData)
|
||||
})
|
||||
@@ -549,7 +558,7 @@ class Render {
|
||||
const index = parent.nodeData.children.findIndex(item => {
|
||||
return item.data.uid === node.uid
|
||||
})
|
||||
const newNodeList = createUidForAppointNodes(simpleDeepClone(nodeList))
|
||||
const newNodeList = createUidForAppointNodes(simpleDeepClone(nodeList), true)
|
||||
parent.nodeData.children.splice(
|
||||
index + 1,
|
||||
0,
|
||||
@@ -610,7 +619,7 @@ class Render {
|
||||
...params,
|
||||
...(appointData || {})
|
||||
},
|
||||
children: [...createUidForAppointNodes(appointChildren)]
|
||||
children: [...createUidForAppointNodes(appointChildren, true)]
|
||||
}
|
||||
node.nodeData.children.push(newNode)
|
||||
// 插入子节点时自动展开子节点
|
||||
@@ -650,7 +659,7 @@ class Render {
|
||||
if (!node.nodeData.children) {
|
||||
node.nodeData.children = []
|
||||
}
|
||||
childList = createUidForAppointNodes(childList)
|
||||
childList = createUidForAppointNodes(childList, true)
|
||||
node.nodeData.children.push(...childList)
|
||||
// 插入子节点时自动展开子节点
|
||||
node.nodeData.data.expand = true
|
||||
@@ -1062,7 +1071,9 @@ class Render {
|
||||
this.activeNodeList.forEach(node => {
|
||||
node.nodeData.children.push(
|
||||
...data.map(item => {
|
||||
return simpleDeepClone(item)
|
||||
const newData = simpleDeepClone(item)
|
||||
createUidForAppointNodes([newData], true)
|
||||
return newData
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import nodeExpandBtnMethods from './nodeExpandBtn'
|
||||
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
||||
import nodeCreateContentsMethods from './nodeCreateContents'
|
||||
import nodeExpandBtnPlaceholderRectMethods from './nodeExpandBtnPlaceholderRect'
|
||||
import nodeCooperateMethods from './nodeCooperate'
|
||||
import { CONSTANTS } from '../../../constants/constant'
|
||||
|
||||
// 节点类
|
||||
@@ -55,6 +56,8 @@ class Node {
|
||||
this.parent = opt.parent || null
|
||||
// 子节点
|
||||
this.children = opt.children || []
|
||||
// 当前同时操作该节点的用户列表
|
||||
this.userList = []
|
||||
// 节点内容的容器
|
||||
this.group = null
|
||||
this.shapeNode = null // 节点形状节点
|
||||
@@ -74,6 +77,7 @@ class Node {
|
||||
this._openExpandNode = null
|
||||
this._closeExpandNode = null
|
||||
this._fillExpandNode = null
|
||||
this._userListGroup = null
|
||||
this._lines = []
|
||||
this._generalizationLine = null
|
||||
this._generalizationNode = null
|
||||
@@ -121,6 +125,12 @@ class Node {
|
||||
Object.keys(nodeCreateContentsMethods).forEach(item => {
|
||||
this[item] = nodeCreateContentsMethods[item].bind(this)
|
||||
})
|
||||
// 协同相关
|
||||
if (this.mindMap.cooperate) {
|
||||
Object.keys(nodeCooperateMethods).forEach((item) => {
|
||||
this[item] = nodeCooperateMethods[item].bind(this)
|
||||
})
|
||||
}
|
||||
// 初始化
|
||||
this.getSize()
|
||||
}
|
||||
@@ -283,6 +293,8 @@ class Node {
|
||||
this.group.add(this.shapeNode)
|
||||
// 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示
|
||||
this.renderExpandBtnPlaceholderRect()
|
||||
// 创建协同头像节点
|
||||
if (this.createUserListNode) this.createUserListNode()
|
||||
// 概要节点添加一个带所属节点id的类名
|
||||
if (this.isGeneralization && this.generalizationBelongNode) {
|
||||
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
||||
@@ -527,6 +539,8 @@ class Node {
|
||||
}
|
||||
// 更新概要
|
||||
this.renderGeneralization()
|
||||
// 更新协同头像
|
||||
if (this.updateUserListNode) this.updateUserListNode()
|
||||
// 更新节点位置
|
||||
let t = this.group.transform()
|
||||
// // 如果上次不在可视区内,且本次也不在,那么直接返回
|
||||
|
||||
104
simple-mind-map/src/core/render/node/nodeCooperate.js
Normal file
104
simple-mind-map/src/core/render/node/nodeCooperate.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Circle, G, Text, Image } from '@svgdotjs/svg.js'
|
||||
import { generateColorByContent } from '../../../utils/index'
|
||||
|
||||
// 协同相关功能
|
||||
|
||||
// 创建容器
|
||||
function createUserListNode() {
|
||||
// 如果没有注册协作插件,那么需要创建
|
||||
if (!this.mindMap.cooperate) return
|
||||
this._userListGroup = new G()
|
||||
this.group.add(this._userListGroup)
|
||||
}
|
||||
|
||||
// 创建文本头像
|
||||
function createTextAvatar(item) {
|
||||
const { avatarSize, fontSize } = this.mindMap.opt.cooperateStyle
|
||||
const g = new G()
|
||||
const str = item.isMore ? item.name : String(item.name)[0]
|
||||
// 圆
|
||||
const circle = new Circle().size(avatarSize, avatarSize)
|
||||
circle.fill({
|
||||
color: item.color || generateColorByContent(str)
|
||||
})
|
||||
// 文本
|
||||
const text = new Text()
|
||||
.text(str)
|
||||
.fill({
|
||||
color: '#fff'
|
||||
})
|
||||
.css({
|
||||
'font-size': fontSize
|
||||
})
|
||||
.dx(-fontSize / 2)
|
||||
.dy((avatarSize - fontSize) / 2)
|
||||
g.add(circle).add(text)
|
||||
return g
|
||||
}
|
||||
|
||||
// 创建图片头像
|
||||
function createImageAvatar(item) {
|
||||
const { avatarSize } = this.mindMap.opt.cooperateStyle
|
||||
return new Image().load(item.avatar).size(avatarSize, avatarSize)
|
||||
}
|
||||
|
||||
// 更新渲染
|
||||
function updateUserListNode() {
|
||||
if (!this._userListGroup) return
|
||||
const { avatarSize } = this.mindMap.opt.cooperateStyle
|
||||
this._userListGroup.clear()
|
||||
// 根据当前节点长度计算最多能显示几个
|
||||
const length = this.userList.length
|
||||
const maxShowCount = Math.floor(this.width / avatarSize)
|
||||
const list = []
|
||||
if (length > maxShowCount) {
|
||||
// 如果当前用户数量比最多能显示的多,最后需要显示一个提示信息
|
||||
list.push(...this.userList.slice(0, maxShowCount - 1), {
|
||||
isMore: true,
|
||||
name: '+' + (length - maxShowCount + 1)
|
||||
})
|
||||
} else {
|
||||
list.push(...this.userList)
|
||||
}
|
||||
list.forEach((item, index) => {
|
||||
let node = null
|
||||
if (item.avatar) {
|
||||
node = this.createImageAvatar(item)
|
||||
} else {
|
||||
node = this.createTextAvatar(item)
|
||||
}
|
||||
node.x(index * avatarSize).cy(-avatarSize / 2)
|
||||
this._userListGroup.add(node)
|
||||
})
|
||||
}
|
||||
|
||||
// 添加用户
|
||||
function addUser(userInfo) {
|
||||
if (
|
||||
this.userList.find(item => {
|
||||
return item.id == userInfo.id
|
||||
})
|
||||
)
|
||||
return
|
||||
this.userList.push(userInfo)
|
||||
this.updateUserListNode()
|
||||
}
|
||||
|
||||
// 移除用户
|
||||
function removeUser(userInfo) {
|
||||
const index = this.userList.findIndex(item => {
|
||||
return item.id == userInfo.id
|
||||
})
|
||||
if (index === -1) return
|
||||
this.userList.splice(index, 1)
|
||||
this.updateUserListNode()
|
||||
}
|
||||
|
||||
export default {
|
||||
createUserListNode,
|
||||
updateUserListNode,
|
||||
createTextAvatar,
|
||||
createImageAvatar,
|
||||
addUser,
|
||||
removeUser
|
||||
}
|
||||
@@ -129,6 +129,10 @@ class Base {
|
||||
this.renderer.addActiveNode(newNode)
|
||||
}
|
||||
}
|
||||
// 如果当前节点在激活节点列表里,那么添加上激活的状态
|
||||
if (this.mindMap.renderer.findActiveNodeIndex(newNode) !== -1) {
|
||||
newNode.nodeData.data.isActive = true
|
||||
}
|
||||
// 根节点
|
||||
if (isRoot) {
|
||||
newNode.isRoot = true
|
||||
|
||||
324
simple-mind-map/src/plugins/Cooperate.js
Normal file
324
simple-mind-map/src/plugins/Cooperate.js
Normal file
@@ -0,0 +1,324 @@
|
||||
import * as Y from 'yjs'
|
||||
import { WebrtcProvider } from 'y-webrtc'
|
||||
import { isSameObject, simpleDeepClone, getType, isUndef } from '../utils/index'
|
||||
|
||||
// 协同插件
|
||||
class Cooperate {
|
||||
constructor(opt) {
|
||||
this.opt = opt
|
||||
this.mindMap = opt.mindMap
|
||||
// yjs文档
|
||||
this.ydoc = new Y.Doc()
|
||||
// 共享数据
|
||||
this.ymap = null
|
||||
// 连接提供者
|
||||
this.provider = null
|
||||
// 感知数据
|
||||
this.awareness = null
|
||||
this.currentAwarenessData = []
|
||||
// 当前的平级对象类型的思维导图数据
|
||||
this.currentData = null
|
||||
// 用户信息
|
||||
this.userInfo = null
|
||||
// 绑定事件
|
||||
this.bindEvent()
|
||||
// 处理实例化时传入的思维导图数据
|
||||
if (this.mindMap.opt.data) {
|
||||
this.initData(this.mindMap.opt.data)
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
initData(data) {
|
||||
data = simpleDeepClone(data)
|
||||
// 解绑原来的数据
|
||||
if (this.ymap) {
|
||||
this.ymap.unobserve(this.onObserve)
|
||||
}
|
||||
// 创建共享数据
|
||||
this.ymap = this.ydoc.getMap()
|
||||
// 思维导图树结构转平级对象结构
|
||||
this.currentData = this.transformTreeDataToObject(data)
|
||||
// 将思维导图数据添加到共享数据中
|
||||
Object.keys(this.currentData).forEach(uid => {
|
||||
this.ymap.set(uid, this.currentData[uid])
|
||||
})
|
||||
// 监听数据同步
|
||||
this.onObserve = this.onObserve.bind(this)
|
||||
this.ymap.observe(this.onObserve)
|
||||
}
|
||||
|
||||
// 获取yjs doc实例
|
||||
getDoc() {
|
||||
return this.ydoc
|
||||
}
|
||||
|
||||
// 设置连接提供者
|
||||
setProvider(provider, webrtcProviderConfig = {}) {
|
||||
const { roomName, signalingList, ...otherConfig } = webrtcProviderConfig
|
||||
this.provider =
|
||||
provider ||
|
||||
new WebrtcProvider(roomName, this.ydoc, {
|
||||
signaling: signalingList,
|
||||
...otherConfig
|
||||
})
|
||||
this.awareness = this.provider.awareness
|
||||
|
||||
// 监听状态同步事件
|
||||
this.onAwareness = this.onAwareness.bind(this)
|
||||
this.awareness.on('change', this.onAwareness)
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
// 监听思维导图改变
|
||||
this.onDataChange = this.onDataChange.bind(this)
|
||||
this.mindMap.on('data_change', this.onDataChange)
|
||||
|
||||
// 监听思维导图节点激活事件
|
||||
this.onNodeActive = this.onNodeActive.bind(this)
|
||||
this.mindMap.on('node_active', this.onNodeActive)
|
||||
|
||||
// 监听设置思维导图数据事件
|
||||
this.initData = this.initData.bind(this)
|
||||
this.mindMap.on('set_data', this.initData)
|
||||
}
|
||||
|
||||
// 解绑事件
|
||||
unBindEvent() {
|
||||
if (this.ymap) {
|
||||
this.ymap.unobserve(this.onObserve)
|
||||
}
|
||||
this.mindMap.off('data_change', this.onDataChange)
|
||||
this.mindMap.off('node_active', this.onNodeActive)
|
||||
this.mindMap.off('set_data', this.initData)
|
||||
this.ydoc.destroy()
|
||||
}
|
||||
|
||||
// 数据同步时的处理,更新当前思维导图
|
||||
onObserve(event) {
|
||||
const data = event.target.toJSON()
|
||||
// 如果数据没有改变直接返回
|
||||
if (isSameObject(data, this.currentData)) return
|
||||
this.currentData = data
|
||||
// 平级对象转树结构
|
||||
const res = this.transformObjectToTreeData(data)
|
||||
if (!res) return
|
||||
// 更新思维导图画布
|
||||
this.mindMap.renderer.setData(res)
|
||||
this.mindMap.render()
|
||||
this.mindMap.command.addHistory()
|
||||
}
|
||||
|
||||
// 当前思维导图改变后的处理,触发同步
|
||||
onDataChange(data) {
|
||||
const res = this.transformTreeDataToObject(data)
|
||||
this.updateChanges(res)
|
||||
}
|
||||
|
||||
// 找出更新点
|
||||
updateChanges(data) {
|
||||
const oldData = this.currentData
|
||||
this.currentData = data
|
||||
this.ydoc.transact(() => {
|
||||
// 找出新增的或修改的
|
||||
Object.keys(data).forEach(uid => {
|
||||
// 新增的或已经存在的,如果数据发生了改变
|
||||
if (!oldData[uid] || !isSameObject(oldData[uid], data[uid])) {
|
||||
this.ymap.set(uid, data[uid])
|
||||
}
|
||||
})
|
||||
// 找出删除的
|
||||
Object.keys(oldData).forEach(uid => {
|
||||
if (!data[uid]) {
|
||||
this.ymap.delete(uid)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 节点激活状态改变后触发感知数据同步
|
||||
onNodeActive(node, nodeList) {
|
||||
if (this.userInfo) {
|
||||
this.awareness.setLocalStateField(this.userInfo.name, {
|
||||
// 用户信息
|
||||
userInfo: {
|
||||
...this.userInfo
|
||||
},
|
||||
// 当前激活的节点id列表
|
||||
nodeIdList: nodeList.map(item => {
|
||||
return item.uid
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 设置用户信息
|
||||
/**
|
||||
* {
|
||||
* id: '', // 必传,用户唯一的id
|
||||
* name: '', // 用户名称。name和avatar两个只传一个即可,如果都传了,会显示avatar
|
||||
* avatar: '', // 用户头像
|
||||
* color: '' // 如果没有传头像,那么会以一个圆形来显示名称的第一个字,文字的颜色为白色,圆的颜色可以通过该字段设置
|
||||
* }
|
||||
**/
|
||||
setUserInfo(userInfo) {
|
||||
if (
|
||||
getType(userInfo) !== 'Object' ||
|
||||
isUndef(userInfo.id) ||
|
||||
(isUndef(userInfo.name) && isUndef(userInfo.avatar))
|
||||
)
|
||||
return
|
||||
this.userInfo = userInfo || null
|
||||
}
|
||||
|
||||
// 监听感知数据同步事件
|
||||
onAwareness() {
|
||||
const walk = (list, callback) => {
|
||||
list.forEach(value => {
|
||||
const userName = Object.keys(value)[0]
|
||||
if (!userName) return
|
||||
const data = value[userName]
|
||||
const userInfo = data.userInfo
|
||||
const nodeIdList = data.nodeIdList
|
||||
nodeIdList.forEach(uid => {
|
||||
const node = this.mindMap.renderer.findNodeByUid(uid)
|
||||
if (node) {
|
||||
callback(node, userInfo)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
// 清除之前的数据
|
||||
walk(this.currentAwarenessData, (node, userInfo) => {
|
||||
node.removeUser(userInfo)
|
||||
})
|
||||
// 设置当前数据
|
||||
const data = Array.from(this.awareness.getStates().values())
|
||||
this.currentAwarenessData = data
|
||||
walk(data, (node, userInfo) => {
|
||||
// 不显示自己
|
||||
if (userInfo.id === this.userInfo.id) return
|
||||
node.addUser(userInfo)
|
||||
})
|
||||
}
|
||||
|
||||
// 将树结构转平级对象
|
||||
/*
|
||||
{
|
||||
data: {
|
||||
uid: 'xxx'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
data: {
|
||||
uid: 'xxx'
|
||||
},
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
转为:
|
||||
{
|
||||
uid: {
|
||||
children: [uid1, uid2],
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
transformTreeDataToObject(data) {
|
||||
const res = {}
|
||||
const walk = (root, parent) => {
|
||||
const uid = root.data.uid
|
||||
if (parent) {
|
||||
parent.children.push(uid)
|
||||
}
|
||||
res[uid] = {
|
||||
isRoot: !parent,
|
||||
data: {
|
||||
...root.data
|
||||
},
|
||||
children: []
|
||||
}
|
||||
if (root.children && root.children.length > 0) {
|
||||
root.children.forEach(item => {
|
||||
walk(item, res[uid])
|
||||
})
|
||||
}
|
||||
}
|
||||
walk(data, null)
|
||||
return res
|
||||
}
|
||||
|
||||
// 找到父节点的uid
|
||||
findParentUid(data, targetUid) {
|
||||
const uids = Object.keys(data)
|
||||
let res = ''
|
||||
uids.forEach(uid => {
|
||||
const children = data[uid].children
|
||||
const isParent =
|
||||
children.findIndex(childUid => {
|
||||
return childUid === targetUid
|
||||
}) !== -1
|
||||
if (isParent) {
|
||||
res = uid
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// 将平级对象转树结构
|
||||
transformObjectToTreeData(data) {
|
||||
const uids = Object.keys(data)
|
||||
if (uids.length <= 0) return null
|
||||
const rootKey = uids.find(uid => {
|
||||
return data[uid].isRoot
|
||||
})
|
||||
if (!rootKey || !data[rootKey]) return null
|
||||
// 根节点
|
||||
const res = {
|
||||
data: simpleDeepClone(data[rootKey].data),
|
||||
children: []
|
||||
}
|
||||
const map = {}
|
||||
map[rootKey] = res
|
||||
uids.forEach(uid => {
|
||||
const parentUid = this.findParentUid(data, uid)
|
||||
const cur = data[uid]
|
||||
const node = map[uid] || {
|
||||
data: simpleDeepClone(cur.data),
|
||||
children: []
|
||||
}
|
||||
if (!map[uid]) {
|
||||
map[uid] = node
|
||||
}
|
||||
if (parentUid) {
|
||||
const index = data[parentUid].children.findIndex(item => {
|
||||
return item === uid
|
||||
})
|
||||
if (!map[parentUid]) {
|
||||
map[parentUid] = {
|
||||
data: simpleDeepClone(data[parentUid].data),
|
||||
children: []
|
||||
}
|
||||
}
|
||||
map[parentUid].children[index] = node
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// 插件被移除前做的事情
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
Cooperate.instanceName = 'cooperate'
|
||||
|
||||
export default Cooperate
|
||||
@@ -89,23 +89,28 @@ class Select {
|
||||
}
|
||||
)
|
||||
})
|
||||
this.mindMap.on('mouseup', () => {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.checkTriggerNodeActiveEvent()
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
this.isMousedown = false
|
||||
this.cacheActiveList = []
|
||||
if (this.rect) this.rect.remove()
|
||||
this.rect = null
|
||||
setTimeout(() => {
|
||||
this.isSelecting = false
|
||||
}, 0)
|
||||
})
|
||||
this.onMouseup = this.onMouseup.bind(this)
|
||||
this.mindMap.on('mouseup', this.onMouseup)
|
||||
this.mindMap.on('node_mouseup', this.onMouseup)
|
||||
}
|
||||
|
||||
// 结束框选
|
||||
onMouseup() {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.checkTriggerNodeActiveEvent()
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
this.isMousedown = false
|
||||
this.cacheActiveList = []
|
||||
if (this.rect) this.rect.remove()
|
||||
this.rect = null
|
||||
setTimeout(() => {
|
||||
this.isSelecting = false
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// 如果激活节点改变了,那么触发事件
|
||||
@@ -184,6 +189,7 @@ class Select {
|
||||
|
||||
// 创建矩形
|
||||
createRect(x, y) {
|
||||
if (this.rect) this.rect.remove()
|
||||
this.rect = this.mindMap.svg
|
||||
.polygon()
|
||||
.stroke({
|
||||
|
||||
@@ -167,11 +167,13 @@ export const copyNodeTree = (
|
||||
tree,
|
||||
root,
|
||||
removeActiveState = false,
|
||||
keepId = false
|
||||
removeId = true
|
||||
) => {
|
||||
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
|
||||
// 重新创建节点uid,因为节点uid不能重复
|
||||
if (!keepId) {
|
||||
// 移除节点uid
|
||||
if (removeId) {
|
||||
delete tree.data.uid
|
||||
} else if (!tree.data.uid) {// 否则保留或生成
|
||||
tree.data.uid = createUid()
|
||||
}
|
||||
if (removeActiveState) {
|
||||
@@ -180,7 +182,7 @@ export const copyNodeTree = (
|
||||
tree.children = []
|
||||
if (root.children && root.children.length > 0) {
|
||||
root.children.forEach((item, index) => {
|
||||
tree.children[index] = copyNodeTree({}, item, removeActiveState, keepId)
|
||||
tree.children[index] = copyNodeTree({}, item, removeActiveState, removeId)
|
||||
})
|
||||
} else if (
|
||||
root.nodeData &&
|
||||
@@ -188,7 +190,7 @@ export const copyNodeTree = (
|
||||
root.nodeData.children.length > 0
|
||||
) {
|
||||
root.nodeData.children.forEach((item, index) => {
|
||||
tree.children[index] = copyNodeTree({}, item, removeActiveState, keepId)
|
||||
tree.children[index] = copyNodeTree({}, item, removeActiveState, removeId)
|
||||
})
|
||||
}
|
||||
return tree
|
||||
@@ -766,14 +768,15 @@ export const addDataToAppointNodes = (appointNodes, data = {}) => {
|
||||
return appointNodes
|
||||
}
|
||||
|
||||
// 给指定的节点列表树数据添加uid,如果不存在的话,会修改原数据
|
||||
export const createUidForAppointNodes = appointNodes => {
|
||||
// 给指定的节点列表树数据添加uid,会修改原数据
|
||||
// createNewId默认为false,即如果节点不存在uid的话,会创建新的uid。如果传true,那么无论节点数据原来是否存在uid,都会创建新的uid
|
||||
export const createUidForAppointNodes = (appointNodes, createNewId = false) => {
|
||||
const walk = list => {
|
||||
list.forEach(node => {
|
||||
if (!node.data) {
|
||||
node.data = {}
|
||||
}
|
||||
if (isUndef(node.data.uid)) {
|
||||
if (createNewId || isUndef(node.data.uid)) {
|
||||
node.data.uid = createUid()
|
||||
}
|
||||
if (node.children && node.children.length > 0) {
|
||||
|
||||
18
simple-mind-map/types/index.d.ts
vendored
18
simple-mind-map/types/index.d.ts
vendored
@@ -95,6 +95,10 @@ declare class MindMap {
|
||||
beingDragNodeOpacity: number;
|
||||
};
|
||||
tagsColorMap: {};
|
||||
cooperateStyle: {
|
||||
avatarSize: number;
|
||||
fontSize: number;
|
||||
};
|
||||
});
|
||||
opt: any;
|
||||
el: any;
|
||||
@@ -159,14 +163,14 @@ declare class MindMap {
|
||||
destroy(): void;
|
||||
}
|
||||
declare namespace MindMap {
|
||||
let pluginList: any[];
|
||||
const pluginList: any[];
|
||||
function usePlugin(plugin: any, opt?: {}): typeof MindMap;
|
||||
function hasPlugin(plugin: any): number;
|
||||
function defineTheme(name: any, config?: {}): Error;
|
||||
}
|
||||
import Event from './src/core/event/Event';
|
||||
import KeyCommand from './src/core/command/KeyCommand';
|
||||
import Command from './src/core/command/Command';
|
||||
import Render from './src/core/render/Render';
|
||||
import View from './src/core/view/View';
|
||||
import BatchExecution from './src/utils/BatchExecution';
|
||||
import Event from "./src/core/event/Event";
|
||||
import KeyCommand from "./src/core/command/KeyCommand";
|
||||
import Command from "./src/core/command/Command";
|
||||
import Render from "./src/core/render/Render";
|
||||
import View from "./src/core/view/View";
|
||||
import BatchExecution from "./src/utils/BatchExecution";
|
||||
|
||||
112
simple-mind-map/types/src/constants/constant.d.ts
vendored
112
simple-mind-map/types/src/constants/constant.d.ts
vendored
@@ -4,81 +4,81 @@ export const themeList: {
|
||||
dark: boolean;
|
||||
}[];
|
||||
export namespace CONSTANTS {
|
||||
let CHANGE_THEME: string;
|
||||
let CHANGE_LAYOUT: string;
|
||||
let SET_DATA: string;
|
||||
let TRANSFORM_TO_NORMAL_NODE: string;
|
||||
const CHANGE_THEME: string;
|
||||
const CHANGE_LAYOUT: string;
|
||||
const SET_DATA: string;
|
||||
const TRANSFORM_TO_NORMAL_NODE: string;
|
||||
namespace MODE {
|
||||
let READONLY: string;
|
||||
let EDIT: string;
|
||||
const READONLY: string;
|
||||
const EDIT: string;
|
||||
}
|
||||
namespace LAYOUT {
|
||||
let LOGICAL_STRUCTURE: string;
|
||||
let MIND_MAP: string;
|
||||
let ORGANIZATION_STRUCTURE: string;
|
||||
let CATALOG_ORGANIZATION: string;
|
||||
let TIMELINE: string;
|
||||
let TIMELINE2: string;
|
||||
let FISHBONE: string;
|
||||
let VERTICAL_TIMELINE: string;
|
||||
const LOGICAL_STRUCTURE: string;
|
||||
const MIND_MAP: string;
|
||||
const ORGANIZATION_STRUCTURE: string;
|
||||
const CATALOG_ORGANIZATION: string;
|
||||
const TIMELINE: string;
|
||||
const TIMELINE2: string;
|
||||
const FISHBONE: string;
|
||||
const VERTICAL_TIMELINE: string;
|
||||
}
|
||||
namespace DIR {
|
||||
let UP: string;
|
||||
let LEFT: string;
|
||||
let DOWN: string;
|
||||
let RIGHT: string;
|
||||
const UP: string;
|
||||
const LEFT: string;
|
||||
const DOWN: string;
|
||||
const RIGHT: string;
|
||||
}
|
||||
namespace KEY_DIR {
|
||||
let LEFT_1: string;
|
||||
const LEFT_1: string;
|
||||
export { LEFT_1 as LEFT };
|
||||
let UP_1: string;
|
||||
const UP_1: string;
|
||||
export { UP_1 as UP };
|
||||
let RIGHT_1: string;
|
||||
const RIGHT_1: string;
|
||||
export { RIGHT_1 as RIGHT };
|
||||
let DOWN_1: string;
|
||||
const DOWN_1: string;
|
||||
export { DOWN_1 as DOWN };
|
||||
}
|
||||
namespace SHAPE {
|
||||
let RECTANGLE: string;
|
||||
let DIAMOND: string;
|
||||
let PARALLELOGRAM: string;
|
||||
let ROUNDED_RECTANGLE: string;
|
||||
let OCTAGONAL_RECTANGLE: string;
|
||||
let OUTER_TRIANGULAR_RECTANGLE: string;
|
||||
let INNER_TRIANGULAR_RECTANGLE: string;
|
||||
let ELLIPSE: string;
|
||||
let CIRCLE: string;
|
||||
const RECTANGLE: string;
|
||||
const DIAMOND: string;
|
||||
const PARALLELOGRAM: string;
|
||||
const ROUNDED_RECTANGLE: string;
|
||||
const OCTAGONAL_RECTANGLE: string;
|
||||
const OUTER_TRIANGULAR_RECTANGLE: string;
|
||||
const INNER_TRIANGULAR_RECTANGLE: string;
|
||||
const ELLIPSE: string;
|
||||
const CIRCLE: string;
|
||||
}
|
||||
namespace MOUSE_WHEEL_ACTION {
|
||||
let ZOOM: string;
|
||||
let MOVE: string;
|
||||
const ZOOM: string;
|
||||
const MOVE: string;
|
||||
}
|
||||
namespace INIT_ROOT_NODE_POSITION {
|
||||
let LEFT_2: string;
|
||||
const LEFT_2: string;
|
||||
export { LEFT_2 as LEFT };
|
||||
export let TOP: string;
|
||||
let RIGHT_2: string;
|
||||
export const TOP: string;
|
||||
const RIGHT_2: string;
|
||||
export { RIGHT_2 as RIGHT };
|
||||
export let BOTTOM: string;
|
||||
export let CENTER: string;
|
||||
export const BOTTOM: string;
|
||||
export const CENTER: string;
|
||||
}
|
||||
namespace LAYOUT_GROW_DIR {
|
||||
let LEFT_3: string;
|
||||
const LEFT_3: string;
|
||||
export { LEFT_3 as LEFT };
|
||||
let TOP_1: string;
|
||||
const TOP_1: string;
|
||||
export { TOP_1 as TOP };
|
||||
let RIGHT_3: string;
|
||||
const RIGHT_3: string;
|
||||
export { RIGHT_3 as RIGHT };
|
||||
let BOTTOM_1: string;
|
||||
const BOTTOM_1: string;
|
||||
export { BOTTOM_1 as BOTTOM };
|
||||
}
|
||||
namespace PASTE_TYPE {
|
||||
let CLIP_BOARD: string;
|
||||
let CANVAS: string;
|
||||
const CLIP_BOARD: string;
|
||||
const CANVAS: string;
|
||||
}
|
||||
namespace SCROLL_BAR_DIR {
|
||||
let VERTICAL: string;
|
||||
let HORIZONTAL: string;
|
||||
const VERTICAL: string;
|
||||
const HORIZONTAL: string;
|
||||
}
|
||||
}
|
||||
export const initRootNodePositionMap: {
|
||||
@@ -91,19 +91,19 @@ export const layoutList: {
|
||||
export const layoutValueList: string[];
|
||||
export const nodeDataNoStylePropList: string[];
|
||||
export namespace commonCaches {
|
||||
let measureCustomNodeContentSizeEl: any;
|
||||
let measureRichtextNodeTextSizeEl: any;
|
||||
const measureCustomNodeContentSizeEl: any;
|
||||
const measureRichtextNodeTextSizeEl: any;
|
||||
}
|
||||
export namespace ERROR_TYPES {
|
||||
let READ_CLIPBOARD_ERROR: string;
|
||||
let PARSE_PASTE_DATA_ERROR: string;
|
||||
let CUSTOM_HANDLE_CLIPBOARD_TEXT_ERROR: string;
|
||||
let LOAD_CLIPBOARD_IMAGE_ERROR: string;
|
||||
let BEFORE_TEXT_EDIT_ERROR: string;
|
||||
let EXPORT_ERROR: string;
|
||||
const READ_CLIPBOARD_ERROR: string;
|
||||
const PARSE_PASTE_DATA_ERROR: string;
|
||||
const CUSTOM_HANDLE_CLIPBOARD_TEXT_ERROR: string;
|
||||
const LOAD_CLIPBOARD_IMAGE_ERROR: string;
|
||||
const BEFORE_TEXT_EDIT_ERROR: string;
|
||||
const EXPORT_ERROR: string;
|
||||
}
|
||||
export namespace a4Size {
|
||||
let width: number;
|
||||
let height: number;
|
||||
const width: number;
|
||||
const height: number;
|
||||
}
|
||||
export const cssContent: "\n /* 鼠标hover和激活时渲染的矩形 */\n .smm-hover-node{\n display: none;\n opacity: 0.6;\n stroke-width: 1;\n }\n\n .smm-node:not(.smm-node-dragging):hover .smm-hover-node{\n display: block;\n }\n\n .smm-node.active .smm-hover-node{\n display: block;\n opacity: 1;\n stroke-width: 2;\n }\n";
|
||||
|
||||
@@ -1,95 +1,100 @@
|
||||
export namespace defaultOpt {
|
||||
let readonly: boolean;
|
||||
let layout: string;
|
||||
let fishboneDeg: number;
|
||||
let theme: string;
|
||||
let themeConfig: {};
|
||||
let scaleRatio: number;
|
||||
let mouseScaleCenterUseMousePosition: boolean;
|
||||
let maxTag: number;
|
||||
let expandBtnSize: number;
|
||||
let imgTextMargin: number;
|
||||
let textContentMargin: number;
|
||||
let selectTranslateStep: number;
|
||||
let selectTranslateLimit: number;
|
||||
let customNoteContentShow: any;
|
||||
let enableFreeDrag: boolean;
|
||||
const readonly: boolean;
|
||||
const layout: string;
|
||||
const fishboneDeg: number;
|
||||
const theme: string;
|
||||
const themeConfig: {};
|
||||
const scaleRatio: number;
|
||||
const mouseScaleCenterUseMousePosition: boolean;
|
||||
const maxTag: number;
|
||||
const expandBtnSize: number;
|
||||
const imgTextMargin: number;
|
||||
const textContentMargin: number;
|
||||
const selectTranslateStep: number;
|
||||
const selectTranslateLimit: number;
|
||||
const customNoteContentShow: any;
|
||||
const enableFreeDrag: boolean;
|
||||
namespace watermarkConfig {
|
||||
let text: string;
|
||||
let lineSpacing: number;
|
||||
let textSpacing: number;
|
||||
let angle: number;
|
||||
const text: string;
|
||||
const lineSpacing: number;
|
||||
const textSpacing: number;
|
||||
const angle: number;
|
||||
namespace textStyle {
|
||||
let color: string;
|
||||
let opacity: number;
|
||||
let fontSize: number;
|
||||
const color: string;
|
||||
const opacity: number;
|
||||
const fontSize: number;
|
||||
}
|
||||
}
|
||||
let textAutoWrapWidth: number;
|
||||
let customHandleMousewheel: any;
|
||||
let mousewheelAction: string;
|
||||
let mousewheelMoveStep: number;
|
||||
let mousewheelZoomActionReverse: boolean;
|
||||
let defaultInsertSecondLevelNodeText: string;
|
||||
let defaultInsertBelowSecondLevelNodeText: string;
|
||||
const textAutoWrapWidth: number;
|
||||
const customHandleMousewheel: any;
|
||||
const mousewheelAction: string;
|
||||
const mousewheelMoveStep: number;
|
||||
const mousewheelZoomActionReverse: boolean;
|
||||
const defaultInsertSecondLevelNodeText: string;
|
||||
const defaultInsertBelowSecondLevelNodeText: string;
|
||||
namespace expandBtnStyle {
|
||||
let color_1: string;
|
||||
const color_1: string;
|
||||
export { color_1 as color };
|
||||
export let fill: string;
|
||||
let fontSize_1: number;
|
||||
export const fill: string;
|
||||
const fontSize_1: number;
|
||||
export { fontSize_1 as fontSize };
|
||||
export let strokeColor: string;
|
||||
export const strokeColor: string;
|
||||
}
|
||||
namespace expandBtnIcon {
|
||||
let open: string;
|
||||
let close: string;
|
||||
const open: string;
|
||||
const close: string;
|
||||
}
|
||||
function expandBtnNumHandler(num: any): any;
|
||||
let isShowExpandNum: boolean;
|
||||
let enableShortcutOnlyWhenMouseInSvg: boolean;
|
||||
let initRootNodePosition: any;
|
||||
let exportPaddingX: number;
|
||||
let exportPaddingY: number;
|
||||
let nodeTextEditZIndex: number;
|
||||
let nodeNoteTooltipZIndex: number;
|
||||
let isEndNodeTextEditOnClickOuter: boolean;
|
||||
let maxHistoryCount: number;
|
||||
let alwaysShowExpandBtn: boolean;
|
||||
let iconList: any[];
|
||||
let maxNodeCacheCount: number;
|
||||
let defaultAssociativeLineText: string;
|
||||
let fitPadding: number;
|
||||
let enableCtrlKeyNodeSelection: boolean;
|
||||
let useLeftKeySelectionRightKeyDrag: boolean;
|
||||
let beforeTextEdit: any;
|
||||
let isUseCustomNodeContent: boolean;
|
||||
let customCreateNodeContent: any;
|
||||
let customInnerElsAppendTo: any;
|
||||
let nodeDragPlaceholderMaxSize: number;
|
||||
let enableAutoEnterTextEditWhenKeydown: boolean;
|
||||
let richTextEditFakeInPlace: boolean;
|
||||
let customHandleClipboardText: any;
|
||||
let disableMouseWheelZoom: boolean;
|
||||
const isShowExpandNum: boolean;
|
||||
const enableShortcutOnlyWhenMouseInSvg: boolean;
|
||||
const initRootNodePosition: any;
|
||||
const exportPaddingX: number;
|
||||
const exportPaddingY: number;
|
||||
const nodeTextEditZIndex: number;
|
||||
const nodeNoteTooltipZIndex: number;
|
||||
const isEndNodeTextEditOnClickOuter: boolean;
|
||||
const maxHistoryCount: number;
|
||||
const alwaysShowExpandBtn: boolean;
|
||||
const iconList: any[];
|
||||
const maxNodeCacheCount: number;
|
||||
const defaultAssociativeLineText: string;
|
||||
const fitPadding: number;
|
||||
const enableCtrlKeyNodeSelection: boolean;
|
||||
const useLeftKeySelectionRightKeyDrag: boolean;
|
||||
const beforeTextEdit: any;
|
||||
const isUseCustomNodeContent: boolean;
|
||||
const customCreateNodeContent: any;
|
||||
const customInnerElsAppendTo: any;
|
||||
const nodeDragPlaceholderMaxSize: number;
|
||||
const enableAutoEnterTextEditWhenKeydown: boolean;
|
||||
const richTextEditFakeInPlace: boolean;
|
||||
const customHandleClipboardText: any;
|
||||
const disableMouseWheelZoom: boolean;
|
||||
function errorHandler(code: any, error: any): void;
|
||||
let resetCss: string;
|
||||
let enableDblclickReset: boolean;
|
||||
let minExportImgCanvasScale: number;
|
||||
let hoverRectColor: string;
|
||||
let hoverRectPadding: number;
|
||||
let selectTextOnEnterEditText: boolean;
|
||||
let deleteNodeActive: boolean;
|
||||
let autoMoveWhenMouseInEdgeOnDrag: boolean;
|
||||
let fit: boolean;
|
||||
const resetCss: string;
|
||||
const enableDblclickReset: boolean;
|
||||
const minExportImgCanvasScale: number;
|
||||
const hoverRectColor: string;
|
||||
const hoverRectPadding: number;
|
||||
const selectTextOnEnterEditText: boolean;
|
||||
const deleteNodeActive: boolean;
|
||||
const autoMoveWhenMouseInEdgeOnDrag: boolean;
|
||||
const fit: boolean;
|
||||
namespace dragMultiNodeRectConfig {
|
||||
export let width: number;
|
||||
export let height: number;
|
||||
let fill_1: string;
|
||||
export const width: number;
|
||||
export const height: number;
|
||||
const fill_1: string;
|
||||
export { fill_1 as fill };
|
||||
}
|
||||
let dragPlaceholderRectFill: string;
|
||||
const dragPlaceholderRectFill: string;
|
||||
namespace dragOpacityConfig {
|
||||
let cloneNodeOpacity: number;
|
||||
let beingDragNodeOpacity: number;
|
||||
const cloneNodeOpacity: number;
|
||||
const beingDragNodeOpacity: number;
|
||||
}
|
||||
const tagsColorMap: {};
|
||||
namespace cooperateStyle {
|
||||
export const avatarSize: number;
|
||||
const fontSize_2: number;
|
||||
export { fontSize_2 as fontSize };
|
||||
}
|
||||
let tagsColorMap: {};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ declare class Render {
|
||||
currentBeingPasteType: string;
|
||||
setLayout(): void;
|
||||
layout: MindMap | CatalogOrganization | OrganizationStructure | Timeline | VerticalTimeline;
|
||||
setData(data: any): void;
|
||||
bindEvent(): void;
|
||||
registerCommands(): void;
|
||||
selectAll(): void;
|
||||
@@ -87,9 +88,9 @@ declare class Render {
|
||||
expandToNodeUid(uid: any, callback?: () => void): void;
|
||||
findNodeByUid(uid: any): any;
|
||||
}
|
||||
import TextEdit from './TextEdit';
|
||||
import MindMap from '../../layouts/MindMap';
|
||||
import CatalogOrganization from '../../layouts/CatalogOrganization';
|
||||
import OrganizationStructure from '../../layouts/OrganizationStructure';
|
||||
import Timeline from '../../layouts/Timeline';
|
||||
import VerticalTimeline from '../../layouts/VerticalTimeline';
|
||||
import TextEdit from "./TextEdit";
|
||||
import MindMap from "../../layouts/MindMap";
|
||||
import CatalogOrganization from "../../layouts/CatalogOrganization";
|
||||
import OrganizationStructure from "../../layouts/OrganizationStructure";
|
||||
import Timeline from "../../layouts/Timeline";
|
||||
import VerticalTimeline from "../../layouts/VerticalTimeline";
|
||||
|
||||
@@ -25,6 +25,7 @@ declare class Node {
|
||||
isDrag: boolean;
|
||||
parent: any;
|
||||
children: any;
|
||||
userList: any[];
|
||||
group: any;
|
||||
shapeNode: any;
|
||||
hoverNode: any;
|
||||
@@ -42,6 +43,7 @@ declare class Node {
|
||||
_openExpandNode: any;
|
||||
_closeExpandNode: any;
|
||||
_fillExpandNode: any;
|
||||
_userListGroup: any;
|
||||
_lines: any[];
|
||||
_generalizationLine: any;
|
||||
_generalizationNode: any;
|
||||
@@ -114,5 +116,5 @@ declare class Node {
|
||||
getData(key: any): any;
|
||||
hasCustomStyle(): boolean;
|
||||
}
|
||||
import Style from './Style';
|
||||
import Shape from './Shape';
|
||||
import Style from "./Style";
|
||||
import Shape from "./Shape";
|
||||
|
||||
@@ -32,5 +32,5 @@ declare class Style {
|
||||
hoverNode(node: any): void;
|
||||
}
|
||||
declare namespace Style {
|
||||
let cacheStyle: any;
|
||||
const cacheStyle: any;
|
||||
}
|
||||
|
||||
18
simple-mind-map/types/src/core/render/node/nodeCooperate.d.ts
vendored
Normal file
18
simple-mind-map/types/src/core/render/node/nodeCooperate.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
declare namespace _default {
|
||||
export { createUserListNode };
|
||||
export { updateUserListNode };
|
||||
export { createTextAvatar };
|
||||
export { createImageAvatar };
|
||||
export { addUser };
|
||||
export { removeUser };
|
||||
}
|
||||
export default _default;
|
||||
declare function createUserListNode(): void;
|
||||
declare class createUserListNode {
|
||||
_userListGroup: any;
|
||||
}
|
||||
declare function updateUserListNode(): void;
|
||||
declare function createTextAvatar(item: any): any;
|
||||
declare function createImageAvatar(item: any): any;
|
||||
declare function addUser(userInfo: any): void;
|
||||
declare function removeUser(userInfo: any): void;
|
||||
@@ -29,4 +29,4 @@ declare class removeGeneralization {
|
||||
}
|
||||
declare function hideGeneralization(): void;
|
||||
declare function showGeneralization(): void;
|
||||
import Node from './Node';
|
||||
import Node from "./Node";
|
||||
|
||||
2
simple-mind-map/types/src/layouts/Base.d.ts
vendored
2
simple-mind-map/types/src/layouts/Base.d.ts
vendored
@@ -40,4 +40,4 @@ declare class Base {
|
||||
};
|
||||
getNodeActChildrenLength(node: any): any;
|
||||
}
|
||||
import Lru from '../utils/Lru';
|
||||
import Lru from "../utils/Lru";
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
export default CatalogOrganization;
|
||||
declare class CatalogOrganization extends Base {
|
||||
constructor(opt?: {});
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedLeftTopValue(): void;
|
||||
adjustLeftTopValue(): void;
|
||||
updateBrothersLeft(node: any, addWidth: any): void;
|
||||
updateBrothersTop(node: any, addHeight: any): void;
|
||||
renderLine(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -3,7 +3,6 @@ declare class Fishbone extends Base {
|
||||
constructor(opt?: {});
|
||||
indent: number;
|
||||
childIndent: number;
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedLeftTopValue(): void;
|
||||
adjustLeftTopValue(): void;
|
||||
@@ -11,9 +10,6 @@ declare class Fishbone extends Base {
|
||||
updateBrothersLeft(node: any): void;
|
||||
updateBrothersTop(node: any, addHeight: any): void;
|
||||
checkIsTop(node: any): boolean;
|
||||
renderLine(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
export default LogicalStructure;
|
||||
declare class LogicalStructure extends Base {
|
||||
constructor(opt?: {});
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedTopValue(): void;
|
||||
adjustTopValue(): void;
|
||||
updateBrothers(node: any, addHeight: any): void;
|
||||
renderLine(node: any, lines: any, style: any, lineStyle: any): void;
|
||||
renderLineStraight(node: any, lines: any, style: any): any[];
|
||||
renderLineDirect(node: any, lines: any, style: any): any[];
|
||||
renderLineCurve(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
export default MindMap;
|
||||
declare class MindMap extends Base {
|
||||
constructor(opt?: {});
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedTopValue(): void;
|
||||
adjustTopValue(): void;
|
||||
updateBrothers(node: any, leftAddHeight: any, rightAddHeight: any): void;
|
||||
renderLine(node: any, lines: any, style: any, lineStyle: any): void;
|
||||
renderLineStraight(node: any, lines: any, style: any): any[];
|
||||
renderLineDirect(node: any, lines: any, style: any): any[];
|
||||
renderLineCurve(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
export default OrganizationStructure;
|
||||
declare class OrganizationStructure extends Base {
|
||||
constructor(opt?: {});
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedLeftValue(): void;
|
||||
adjustLeftValue(): void;
|
||||
updateBrothers(node: any, addWidth: any): void;
|
||||
renderLine(node: any, lines: any, style: any, lineStyle: any): void;
|
||||
renderLineDirect(node: any, lines: any, style: any): any[];
|
||||
renderLineStraight(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -2,16 +2,12 @@ export default Timeline;
|
||||
declare class Timeline extends Base {
|
||||
constructor(opt: {}, layout: any);
|
||||
layout: any;
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedLeftTopValue(): void;
|
||||
adjustLeftTopValue(): void;
|
||||
getNodeAreaHeight(node: any): number;
|
||||
updateBrothersLeft(node: any): void;
|
||||
updateBrothersTop(node: any, addHeight: any): void;
|
||||
renderLine(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -2,18 +2,14 @@ export default VerticalTimeline;
|
||||
declare class VerticalTimeline extends Base {
|
||||
constructor(opt: {}, layout: any);
|
||||
layout: any;
|
||||
doLayout(callback: any): void;
|
||||
computedBaseValue(): void;
|
||||
computedTopValue(): void;
|
||||
adjustLeftTopValue(): void;
|
||||
updateBrothers(node: any, addHeight: any): void;
|
||||
updateBrothersTop(node: any, addHeight: any): void;
|
||||
renderLine(node: any, lines: any, style: any, lineStyle: any): void;
|
||||
renderLineStraight(node: any, lines: any, style: any): any[];
|
||||
renderLineDirect(node: any, lines: any, style: any): any[];
|
||||
renderLineCurve(node: any, lines: any, style: any): any[];
|
||||
renderExpandBtn(node: any, btn: any): void;
|
||||
renderGeneralization(node: any, gLine: any, gNode: any): void;
|
||||
renderExpandBtnRect(rect: any, expandBtnSize: any, width: any, height: any, node: any): void;
|
||||
}
|
||||
import Base from './Base';
|
||||
import Base from "./Base";
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
declare namespace _default {
|
||||
namespace top {
|
||||
function renderExpandBtn({ node, btn, expandBtnSize, translateX, translateY, width, height }: {
|
||||
node: any;
|
||||
btn: any;
|
||||
expandBtnSize: any;
|
||||
translateX: any;
|
||||
translateY: any;
|
||||
width: any;
|
||||
height: any;
|
||||
}): void;
|
||||
function renderExpandBtn({ node, btn, expandBtnSize, translateX, translateY, width, height }: {
|
||||
node: any;
|
||||
btn: any;
|
||||
@@ -20,11 +29,33 @@ declare namespace _default {
|
||||
maxy: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function renderLine({ node, line, top, x, lineLength, height, expandBtnSize, maxy, ctx }: {
|
||||
node: any;
|
||||
line: any;
|
||||
top: any;
|
||||
x: any;
|
||||
lineLength: any;
|
||||
height: any;
|
||||
expandBtnSize: any;
|
||||
maxy: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function computedLeftTopValue({ layerIndex, node, ctx }: {
|
||||
layerIndex: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function computedLeftTopValue({ layerIndex, node, ctx }: {
|
||||
layerIndex: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueBefore({ node, parent, ctx, layerIndex }: {
|
||||
node: any;
|
||||
parent: any;
|
||||
ctx: any;
|
||||
layerIndex: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueBefore({ node, parent, ctx, layerIndex }: {
|
||||
node: any;
|
||||
parent: any;
|
||||
@@ -36,8 +67,22 @@ declare namespace _default {
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueAfter({ parent, node, ctx }: {
|
||||
parent: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
}
|
||||
namespace bottom {
|
||||
function renderExpandBtn({ node, btn, expandBtnSize, translateX, translateY, width, height }: {
|
||||
node: any;
|
||||
btn: any;
|
||||
expandBtnSize: any;
|
||||
translateX: any;
|
||||
translateY: any;
|
||||
width: any;
|
||||
height: any;
|
||||
}): void;
|
||||
function renderExpandBtn({ node, btn, expandBtnSize, translateX, translateY, width, height }: {
|
||||
node: any;
|
||||
btn: any;
|
||||
@@ -57,11 +102,31 @@ declare namespace _default {
|
||||
miny: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function renderLine({ node, line, top, x, lineLength, height, miny, ctx }: {
|
||||
node: any;
|
||||
line: any;
|
||||
top: any;
|
||||
x: any;
|
||||
lineLength: any;
|
||||
height: any;
|
||||
miny: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function computedLeftTopValue({ layerIndex, node, ctx }: {
|
||||
layerIndex: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function computedLeftTopValue({ layerIndex, node, ctx }: {
|
||||
layerIndex: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueBefore({ node, ctx, layerIndex }: {
|
||||
node: any;
|
||||
ctx: any;
|
||||
layerIndex: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueBefore({ node, ctx, layerIndex }: {
|
||||
node: any;
|
||||
ctx: any;
|
||||
@@ -72,6 +137,11 @@ declare namespace _default {
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
function adjustLeftTopValueAfter({ parent, node, ctx }: {
|
||||
parent: any;
|
||||
node: any;
|
||||
ctx: any;
|
||||
}): void;
|
||||
}
|
||||
}
|
||||
export default _default;
|
||||
|
||||
172
simple-mind-map/types/src/themes/default.d.ts
vendored
172
simple-mind-map/types/src/themes/default.d.ts
vendored
@@ -1,139 +1,139 @@
|
||||
declare namespace _default {
|
||||
let paddingX: number;
|
||||
let paddingY: number;
|
||||
let imgMaxWidth: number;
|
||||
let imgMaxHeight: number;
|
||||
let iconSize: number;
|
||||
let lineWidth: number;
|
||||
let lineColor: string;
|
||||
let lineDasharray: string;
|
||||
let lineStyle: string;
|
||||
let rootLineKeepSameInCurve: boolean;
|
||||
let generalizationLineWidth: number;
|
||||
let generalizationLineColor: string;
|
||||
let generalizationLineMargin: number;
|
||||
let generalizationNodeMargin: number;
|
||||
let associativeLineWidth: number;
|
||||
let associativeLineColor: string;
|
||||
let associativeLineActiveWidth: number;
|
||||
let associativeLineActiveColor: string;
|
||||
let associativeLineTextColor: string;
|
||||
let associativeLineTextFontSize: number;
|
||||
let associativeLineTextLineHeight: number;
|
||||
let associativeLineTextFontFamily: string;
|
||||
let backgroundColor: string;
|
||||
let backgroundImage: string;
|
||||
let backgroundRepeat: string;
|
||||
let backgroundPosition: string;
|
||||
let backgroundSize: string;
|
||||
let nodeUseLineStyle: boolean;
|
||||
const paddingX: number;
|
||||
const paddingY: number;
|
||||
const imgMaxWidth: number;
|
||||
const imgMaxHeight: number;
|
||||
const iconSize: number;
|
||||
const lineWidth: number;
|
||||
const lineColor: string;
|
||||
const lineDasharray: string;
|
||||
const lineStyle: string;
|
||||
const rootLineKeepSameInCurve: boolean;
|
||||
const generalizationLineWidth: number;
|
||||
const generalizationLineColor: string;
|
||||
const generalizationLineMargin: number;
|
||||
const generalizationNodeMargin: number;
|
||||
const associativeLineWidth: number;
|
||||
const associativeLineColor: string;
|
||||
const associativeLineActiveWidth: number;
|
||||
const associativeLineActiveColor: string;
|
||||
const associativeLineTextColor: string;
|
||||
const associativeLineTextFontSize: number;
|
||||
const associativeLineTextLineHeight: number;
|
||||
const associativeLineTextFontFamily: string;
|
||||
const backgroundColor: string;
|
||||
const backgroundImage: string;
|
||||
const backgroundRepeat: string;
|
||||
const backgroundPosition: string;
|
||||
const backgroundSize: string;
|
||||
const nodeUseLineStyle: boolean;
|
||||
namespace root {
|
||||
let shape: string;
|
||||
let fillColor: string;
|
||||
let fontFamily: string;
|
||||
let color: string;
|
||||
let fontSize: number;
|
||||
let fontWeight: string;
|
||||
let fontStyle: string;
|
||||
let lineHeight: number;
|
||||
let borderColor: string;
|
||||
let borderWidth: number;
|
||||
let borderDasharray: string;
|
||||
let borderRadius: number;
|
||||
let textDecoration: string;
|
||||
const shape: string;
|
||||
const fillColor: string;
|
||||
const fontFamily: string;
|
||||
const color: string;
|
||||
const fontSize: number;
|
||||
const fontWeight: string;
|
||||
const fontStyle: string;
|
||||
const lineHeight: number;
|
||||
const borderColor: string;
|
||||
const borderWidth: number;
|
||||
const borderDasharray: string;
|
||||
const borderRadius: number;
|
||||
const textDecoration: string;
|
||||
}
|
||||
namespace second {
|
||||
let shape_1: string;
|
||||
const shape_1: string;
|
||||
export { shape_1 as shape };
|
||||
export let marginX: number;
|
||||
export let marginY: number;
|
||||
let fillColor_1: string;
|
||||
export const marginX: number;
|
||||
export const marginY: number;
|
||||
const fillColor_1: string;
|
||||
export { fillColor_1 as fillColor };
|
||||
let fontFamily_1: string;
|
||||
const fontFamily_1: string;
|
||||
export { fontFamily_1 as fontFamily };
|
||||
let color_1: string;
|
||||
const color_1: string;
|
||||
export { color_1 as color };
|
||||
let fontSize_1: number;
|
||||
const fontSize_1: number;
|
||||
export { fontSize_1 as fontSize };
|
||||
let fontWeight_1: string;
|
||||
const fontWeight_1: string;
|
||||
export { fontWeight_1 as fontWeight };
|
||||
let fontStyle_1: string;
|
||||
const fontStyle_1: string;
|
||||
export { fontStyle_1 as fontStyle };
|
||||
let lineHeight_1: number;
|
||||
const lineHeight_1: number;
|
||||
export { lineHeight_1 as lineHeight };
|
||||
let borderColor_1: string;
|
||||
const borderColor_1: string;
|
||||
export { borderColor_1 as borderColor };
|
||||
let borderWidth_1: number;
|
||||
const borderWidth_1: number;
|
||||
export { borderWidth_1 as borderWidth };
|
||||
let borderDasharray_1: string;
|
||||
const borderDasharray_1: string;
|
||||
export { borderDasharray_1 as borderDasharray };
|
||||
let borderRadius_1: number;
|
||||
const borderRadius_1: number;
|
||||
export { borderRadius_1 as borderRadius };
|
||||
let textDecoration_1: string;
|
||||
const textDecoration_1: string;
|
||||
export { textDecoration_1 as textDecoration };
|
||||
}
|
||||
namespace node {
|
||||
let shape_2: string;
|
||||
const shape_2: string;
|
||||
export { shape_2 as shape };
|
||||
let marginX_1: number;
|
||||
const marginX_1: number;
|
||||
export { marginX_1 as marginX };
|
||||
let marginY_1: number;
|
||||
const marginY_1: number;
|
||||
export { marginY_1 as marginY };
|
||||
let fillColor_2: string;
|
||||
const fillColor_2: string;
|
||||
export { fillColor_2 as fillColor };
|
||||
let fontFamily_2: string;
|
||||
const fontFamily_2: string;
|
||||
export { fontFamily_2 as fontFamily };
|
||||
let color_2: string;
|
||||
const color_2: string;
|
||||
export { color_2 as color };
|
||||
let fontSize_2: number;
|
||||
const fontSize_2: number;
|
||||
export { fontSize_2 as fontSize };
|
||||
let fontWeight_2: string;
|
||||
const fontWeight_2: string;
|
||||
export { fontWeight_2 as fontWeight };
|
||||
let fontStyle_2: string;
|
||||
const fontStyle_2: string;
|
||||
export { fontStyle_2 as fontStyle };
|
||||
let lineHeight_2: number;
|
||||
const lineHeight_2: number;
|
||||
export { lineHeight_2 as lineHeight };
|
||||
let borderColor_2: string;
|
||||
const borderColor_2: string;
|
||||
export { borderColor_2 as borderColor };
|
||||
let borderWidth_2: number;
|
||||
const borderWidth_2: number;
|
||||
export { borderWidth_2 as borderWidth };
|
||||
let borderRadius_2: number;
|
||||
const borderRadius_2: number;
|
||||
export { borderRadius_2 as borderRadius };
|
||||
let borderDasharray_2: string;
|
||||
const borderDasharray_2: string;
|
||||
export { borderDasharray_2 as borderDasharray };
|
||||
let textDecoration_2: string;
|
||||
const textDecoration_2: string;
|
||||
export { textDecoration_2 as textDecoration };
|
||||
}
|
||||
namespace generalization {
|
||||
let shape_3: string;
|
||||
const shape_3: string;
|
||||
export { shape_3 as shape };
|
||||
let marginX_2: number;
|
||||
const marginX_2: number;
|
||||
export { marginX_2 as marginX };
|
||||
let marginY_2: number;
|
||||
const marginY_2: number;
|
||||
export { marginY_2 as marginY };
|
||||
let fillColor_3: string;
|
||||
const fillColor_3: string;
|
||||
export { fillColor_3 as fillColor };
|
||||
let fontFamily_3: string;
|
||||
const fontFamily_3: string;
|
||||
export { fontFamily_3 as fontFamily };
|
||||
let color_3: string;
|
||||
const color_3: string;
|
||||
export { color_3 as color };
|
||||
let fontSize_3: number;
|
||||
const fontSize_3: number;
|
||||
export { fontSize_3 as fontSize };
|
||||
let fontWeight_3: string;
|
||||
const fontWeight_3: string;
|
||||
export { fontWeight_3 as fontWeight };
|
||||
let fontStyle_3: string;
|
||||
const fontStyle_3: string;
|
||||
export { fontStyle_3 as fontStyle };
|
||||
let lineHeight_3: number;
|
||||
const lineHeight_3: number;
|
||||
export { lineHeight_3 as lineHeight };
|
||||
let borderColor_3: string;
|
||||
const borderColor_3: string;
|
||||
export { borderColor_3 as borderColor };
|
||||
let borderWidth_3: number;
|
||||
const borderWidth_3: number;
|
||||
export { borderWidth_3 as borderWidth };
|
||||
let borderDasharray_3: string;
|
||||
const borderDasharray_3: string;
|
||||
export { borderDasharray_3 as borderDasharray };
|
||||
let borderRadius_3: number;
|
||||
const borderRadius_3: number;
|
||||
export { borderRadius_3 as borderRadius };
|
||||
let textDecoration_3: string;
|
||||
const textDecoration_3: string;
|
||||
export { textDecoration_3 as textDecoration };
|
||||
}
|
||||
}
|
||||
|
||||
5
simple-mind-map/types/src/utils/index.d.ts
vendored
5
simple-mind-map/types/src/utils/index.d.ts
vendored
@@ -6,7 +6,7 @@ export function resizeImg(imgUrl: any, maxWidth: any, maxHeight: any): Promise<a
|
||||
export function getStrWithBrFromHtml(str: any): any;
|
||||
export function simpleDeepClone(data: any): any;
|
||||
export function copyRenderTree(tree: any, root: any, removeActiveState?: boolean): any;
|
||||
export function copyNodeTree(tree: any, root: any, removeActiveState?: boolean, keepId?: boolean): any;
|
||||
export function copyNodeTree(tree: any, root: any, removeActiveState?: boolean, removeId?: boolean): any;
|
||||
export function imgToDataUrl(src: any): Promise<any>;
|
||||
export function parseDataUrl(data: any): any;
|
||||
export function downloadFile(file: any, fileName: any): void;
|
||||
@@ -62,8 +62,9 @@ export function checkTwoRectIsOverlap(minx1: any, maxx1: any, miny1: any, maxy1:
|
||||
export function focusInput(el: any): void;
|
||||
export function selectAllInput(el: any): void;
|
||||
export function addDataToAppointNodes(appointNodes: any, data?: {}): any;
|
||||
export function createUidForAppointNodes(appointNodes: any): any;
|
||||
export function createUidForAppointNodes(appointNodes: any, createNewId?: boolean): any;
|
||||
export function formatDataToArray(data: any): any[];
|
||||
export function getNodeIndex(node: any): any;
|
||||
export function generateColorByContent(str: any): string;
|
||||
export function htmlEscape(str: any): any;
|
||||
export function isSameObject(a: any, b: any): boolean;
|
||||
|
||||
2
web/package-lock.json
generated
2
web/package-lock.json
generated
@@ -18488,6 +18488,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",
|
||||
@@ -18500,6 +18501,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"
|
||||
}
|
||||
|
||||
BIN
web/src/assets/avatar/有希.jpg
Normal file
BIN
web/src/assets/avatar/有希.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
web/src/assets/avatar/樊笼.jpg
Normal file
BIN
web/src/assets/avatar/樊笼.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
web/src/assets/avatar/达仁科技.jpg
Normal file
BIN
web/src/assets/avatar/达仁科技.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
@@ -36,6 +36,7 @@ let APIList = [
|
||||
'painter',
|
||||
'scrollbar',
|
||||
'formula',
|
||||
'cooperate',
|
||||
'xmind',
|
||||
'markdown',
|
||||
'utils'
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
## 0.7.3-fix.2
|
||||
|
||||
Fix some issues with collaborative editing:
|
||||
|
||||
1.The position of the new node is incorrect when inserting peer nodes;
|
||||
|
||||
2.Moving a position within a peer node did not trigger an update;
|
||||
|
||||
3.The position of the mobile node inserted as a sibling node is incorrect;
|
||||
|
||||
## 0.7.3-fix.1
|
||||
|
||||
Fix:
|
||||
|
||||
> 1.Fixed some issues where the box selection area did not disappear when multiple nodes were selected.
|
||||
>
|
||||
> 2.Fixed an issue where the box selection area does not disappear when releasing the mouse over multiple selected nodes.
|
||||
>
|
||||
> 3.Fixed rendering anomalies caused by duplicate node uids when pasting nodes multiple times.
|
||||
|
||||
Demo:
|
||||
|
||||
> 1.Add protocol selection function to the hyperlink input box.
|
||||
|
||||
## 0.7.3
|
||||
|
||||
New: 1.Add a Cooperate editing plugin.
|
||||
|
||||
Demo: 1.Fix the automatic closing of the sidebar caused by the formula sidebar component.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
Fix:
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.7.3-fix.2</h2>
|
||||
<p>Fix some issues with collaborative editing:</p>
|
||||
<p>1.The position of the new node is incorrect when inserting peer nodes;</p>
|
||||
<p>2.Moving a position within a peer node did not trigger an update;</p>
|
||||
<p>3.The position of the mobile node inserted as a sibling node is incorrect;</p>
|
||||
<h2>0.7.3-fix.1</h2>
|
||||
<p>Fix:</p>
|
||||
<blockquote>
|
||||
<p>1.Fixed some issues where the box selection area did not disappear when multiple nodes were selected.</p>
|
||||
<p>2.Fixed an issue where the box selection area does not disappear when releasing the mouse over multiple selected nodes.</p>
|
||||
<p>3.Fixed rendering anomalies caused by duplicate node uids when pasting nodes multiple times.</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
<p>1.Add protocol selection function to the hyperlink input box.</p>
|
||||
</blockquote>
|
||||
<h2>0.7.3</h2>
|
||||
<p>New: 1.Add a Cooperate editing plugin.</p>
|
||||
<p>Demo: 1.Fix the automatic closing of the sidebar caused by the formula sidebar component.</p>
|
||||
<h2>0.7.2</h2>
|
||||
<p>Fix:</p>
|
||||
<blockquote>
|
||||
|
||||
@@ -94,6 +94,7 @@ const mindMap = new MindMap({
|
||||
| dragPlaceholderRectFill(v0.7.2+) | String | | The filling color of the schematic rectangle for the new position when dragging nodes. If not transmitted, the default color for the connected line is used | |
|
||||
| dragOpacityConfig(v0.7.2+) | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | The transparency configuration during node dragging, passing an object, and the field meanings are: the transparency of the cloned node or rectangle that follows the mouse movement, and the transparency of the dragged node | |
|
||||
| tagsColorMap(v0.7.2+) | Object | {} | The color of a custom node label can be transferred to an object, where key is the label content to be assigned a color, and value is the color of the label content. If not transferred internally, a corresponding color will be generated based on the label content | |
|
||||
| cooperateStyle(v0.7.3+) | Object | { avatarSize: 22, fontSize: 12 } | The configuration of personnel avatar style during node collaboration editing, with field meanings as follows: avatar size, and if it is a text avatar, the size of the text | |
|
||||
|
||||
### Data structure
|
||||
|
||||
@@ -312,6 +313,7 @@ Listen to an event. Event list:
|
||||
| svg_mouseleave(v0.5.1+) | Triggered when the mouse moves out of the SVG canvas | e(event object) |
|
||||
| node_icon_click(v0.6.10+) | Triggered when clicking on an icon within a node | this(node instance)、item(Click on the icon name)、e(event object) |
|
||||
| view_theme_change(v0.6.12+) | Triggered after calling the setTheme method to set the theme | theme(theme name) |
|
||||
| set_data(v0.7.3+) | Triggered when the setData method is called to dynamically set mind map data | data(New Mind Map Data) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
|
||||
@@ -518,6 +518,13 @@
|
||||
<td>The color of a custom node label can be transferred to an object, where key is the label content to be assigned a color, and value is the color of the label content. If not transferred internally, a corresponding color will be generated based on the label content</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>cooperateStyle(v0.7.3+)</td>
|
||||
<td>Object</td>
|
||||
<td>{ avatarSize: 22, fontSize: 12 }</td>
|
||||
<td>The configuration of personnel avatar style during node collaboration editing, with field meanings as follows: avatar size, and if it is a text avatar, the size of the text</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Data structure</h3>
|
||||
@@ -921,6 +928,11 @@ poor performance and should be used sparingly.</p>
|
||||
<td>Triggered after calling the setTheme method to set the theme</td>
|
||||
<td>theme(theme name)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set_data(v0.7.3+)</td>
|
||||
<td>Triggered when the setData method is called to dynamically set mind map data</td>
|
||||
<td>data(New Mind Map Data)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
|
||||
124
web/src/pages/Doc/en/cooperate/index.md
Normal file
124
web/src/pages/Doc/en/cooperate/index.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Cooperate plugin beta
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
This plugin is used to achieve collaborative editing.
|
||||
|
||||
## Introduce
|
||||
|
||||
This plugin implements collaborative editing through [Yjs](https://github.com/yjs/yjs). The basic principle is to convert the tree data of the mind map into flat object data, and then collaborate through shared data of type [Y.Map](https://docs.yjs.dev/api/shared-types/y.map). That is, when certain operations are performed on the canvas, the 'y.map' object will be updated, and other collaborative clients will receive the updated data, convert it back to tree structure data, and update the canvas to achieve real-time updates.
|
||||
|
||||
To achieve collaboration, the backend is indispensable, and 'Yjs' provides some [Connection Providers](https://docs.yjs.dev/ecosystem/connection-provider). At the same time, it also provides examples of the backend, but it is only the simplest implementation. In actual projects, you should need to rewrite or improve it.
|
||||
|
||||
You can choose the 'Provider' that suits you, and the default is [y-webrtc](https://github.com/yjs/y-webrtc).
|
||||
|
||||
## demo
|
||||
|
||||
If you want to try it through demo, you can do the following steps:
|
||||
|
||||
1. Clone project and installation dependencies:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd mind-map
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
cd ..
|
||||
cd web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
```
|
||||
|
||||
2. Modify `web/src/pages/Edit/components/Edit.vue` file
|
||||
|
||||
To register Cooperate plugin, uncomment the line:
|
||||
|
||||
```js
|
||||
// .usePlugin(Cooperate)// Cooperate plugin
|
||||
```
|
||||
|
||||
Change the signaling server address to your local IP:
|
||||
|
||||
```js
|
||||
// cooperateTest function
|
||||
|
||||
signalingList: ['ws://【your ip】:4444']
|
||||
```
|
||||
|
||||
3. To register a collaborative plugin, uncomment the line:
|
||||
|
||||
```bash
|
||||
// Execute under web path
|
||||
npm run serve
|
||||
```
|
||||
|
||||
4. Start signaling server:
|
||||
|
||||
```bash
|
||||
// Execute under simple-mind-map path
|
||||
npm run wsServe
|
||||
```
|
||||
|
||||
The command executes the 'simple mind map/bin/wsServer.mjs' file, which is directly copied from the [y webrtc](https://github.com/yjs/y-webrtc) repository and may not be complete. Please be cautious when using it for actual projects.
|
||||
|
||||
5. Access the service address in two browsers:
|
||||
|
||||
```
|
||||
http://【your ip】:8080/#/?userName=userName
|
||||
```
|
||||
|
||||
You can set different userNames on different browsers. Then you can edit in one browser and see the automatic update in another browser.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
||||
MindMap.usePlugin(Cooperate)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.cooperate`.
|
||||
|
||||
## Methods
|
||||
|
||||
### getDoc()
|
||||
|
||||
Obtain Yjs doc instance.
|
||||
|
||||
### setProvider(provider, webrtcProviderConfig)
|
||||
|
||||
- `provider`: The connection provider for Yjs can refer to the [Connection Provider](https://docs.yjs.dev/ecosystem/connection-provider), default is `null`
|
||||
|
||||
- `webrtcProviderConfig`: the options of webrtc provider, An object needs to be passed in the following format:
|
||||
|
||||
```js
|
||||
{
|
||||
roomName: '', // Mandatory, room name
|
||||
signalingList: [''],// Mandatory, specify signaling server
|
||||
...// The other config of webrtc provider
|
||||
}
|
||||
```
|
||||
|
||||
For detailed configuration, please refer to [y-webrtc](https://github.com/yjs/y-webrtc)。
|
||||
|
||||
Set the connection provider for Yjs. If 'provider' is not transmitted, 'y webrtc' will be used by default. You can also use other 'providers'.
|
||||
|
||||
If the default 'y webrtc' is used, the necessary configuration needs to be passed in through the second parameter.
|
||||
|
||||
`simple-mind-map/bin/wsServer.mjs` file provides a simple signaling server code for testing and reference.
|
||||
|
||||
### setUserInfo(userInfo)
|
||||
|
||||
- `userInfo`: User information. The format is as follows:
|
||||
|
||||
```js
|
||||
{
|
||||
id: '', // Mandatory, user's unique ID
|
||||
name: '', // User name. Only one name and avatar can be transmitted. If both are transmitted, avatar will be displayed
|
||||
avatar: '', // User profile
|
||||
color: '' // If there is no avatar, the first character of the name will be displayed as a circle, and the color of the text will be white. The color of the circle can be set through this field
|
||||
}
|
||||
```
|
||||
|
||||
Set the current user's information for synchronization and display of perceptual data. If other collaborators activate a node, their avatar will be displayed above that node in your current canvas.
|
||||
109
web/src/pages/Doc/en/cooperate/index.vue
Normal file
109
web/src/pages/Doc/en/cooperate/index.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Cooperate plugin beta</h1>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<p>This plugin is used to achieve collaborative editing.</p>
|
||||
<h2>Introduce</h2>
|
||||
<p>This plugin implements collaborative editing through <a href="https://github.com/yjs/yjs">Yjs</a>. The basic principle is to convert the tree data of the mind map into flat object data, and then collaborate through shared data of type <a href="https://docs.yjs.dev/api/shared-types/y.map">Y.Map</a>. That is, when certain operations are performed on the canvas, the 'y.map' object will be updated, and other collaborative clients will receive the updated data, convert it back to tree structure data, and update the canvas to achieve real-time updates.</p>
|
||||
<p>To achieve collaboration, the backend is indispensable, and 'Yjs' provides some <a href="https://docs.yjs.dev/ecosystem/connection-provider">Connection Providers</a>. At the same time, it also provides examples of the backend, but it is only the simplest implementation. In actual projects, you should need to rewrite or improve it.</p>
|
||||
<p>You can choose the 'Provider' that suits you, and the default is <a href="https://github.com/yjs/y-webrtc">y-webrtc</a>.</p>
|
||||
<h2>demo</h2>
|
||||
<p>If you want to try it through demo, you can do the following steps:</p>
|
||||
<ol>
|
||||
<li>Clone project and installation dependencies:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>git <span class="hljs-built_in">clone</span> https://github.com/wanglin2/mind-map.git
|
||||
<span class="hljs-built_in">cd</span> mind-map
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
<span class="hljs-built_in">cd</span> ..
|
||||
<span class="hljs-built_in">cd</span> web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
</code></pre>
|
||||
<ol start="2">
|
||||
<li>Modify <code>web/src/pages/Edit/components/Edit.vue</code> file</li>
|
||||
</ol>
|
||||
<p>To register Cooperate plugin, uncomment the line:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// .usePlugin(Cooperate)// Cooperate plugin</span>
|
||||
</code></pre>
|
||||
<p>Change the signaling server address to your local IP:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// cooperateTest function</span>
|
||||
|
||||
<span class="hljs-attr">signalingList</span>: [<span class="hljs-string">'ws://【your ip】:4444'</span>]
|
||||
</code></pre>
|
||||
<ol start="3">
|
||||
<li>To register a collaborative plugin, uncomment the line:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>// Execute under web path
|
||||
npm run serve
|
||||
</code></pre>
|
||||
<ol start="4">
|
||||
<li>Start signaling server:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>// Execute under simple-mind-map path
|
||||
npm run wsServe
|
||||
</code></pre>
|
||||
<p>The command executes the 'simple mind map/bin/wsServer.mjs' file, which is directly copied from the <a href="https://github.com/yjs/y-webrtc">y webrtc</a> repository and may not be complete. Please be cautious when using it for actual projects.</p>
|
||||
<ol start="5">
|
||||
<li>Access the service address in two browsers:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>http://【your ip】:8080/#/?userName=userName
|
||||
</code></pre>
|
||||
<p>You can set different userNames on different browsers. Then you can edit in one browser and see the automatic update in another browser.</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> Cooperate <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/plugins/Cooperate.js'</span>
|
||||
MindMap.usePlugin(Cooperate)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.cooperate</code>.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>getDoc()</h3>
|
||||
<p>Obtain Yjs doc instance.</p>
|
||||
<h3>setProvider(provider, webrtcProviderConfig)</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>provider</code>: The connection provider for Yjs can refer to the <a href="https://docs.yjs.dev/ecosystem/connection-provider">Connection Provider</a>, default is <code>null</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>webrtcProviderConfig</code>: the options of webrtc provider, An object needs to be passed in the following format:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">roomName</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// Mandatory, room name</span>
|
||||
<span class="hljs-attr">signalingList</span>: [<span class="hljs-string">''</span>],<span class="hljs-comment">// Mandatory, specify signaling server</span>
|
||||
...<span class="hljs-comment">// The other config of webrtc provider</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>For detailed configuration, please refer to <a href="https://github.com/yjs/y-webrtc">y-webrtc</a>。</p>
|
||||
<p>Set the connection provider for Yjs. If 'provider' is not transmitted, 'y webrtc' will be used by default. You can also use other 'providers'.</p>
|
||||
<p>If the default 'y webrtc' is used, the necessary configuration needs to be passed in through the second parameter.</p>
|
||||
<p><code>simple-mind-map/bin/wsServer.mjs</code> file provides a simple signaling server code for testing and reference.</p>
|
||||
<h3>setUserInfo(userInfo)</h3>
|
||||
<ul>
|
||||
<li><code>userInfo</code>: User information. The format is as follows:</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">id</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// Mandatory, user's unique ID</span>
|
||||
<span class="hljs-attr">name</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// User name. Only one name and avatar can be transmitted. If both are transmitted, avatar will be displayed</span>
|
||||
<span class="hljs-attr">avatar</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// User profile</span>
|
||||
<span class="hljs-attr">color</span>: <span class="hljs-string">''</span> <span class="hljs-comment">// If there is no avatar, the first character of the name will be displayed as a circle, and the color of the text will be white. The color of the circle can be set through this field</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Set the current user's information for synchronization and display of perceptual data. If other collaborators activate a node, their avatar will be displayed above that node in your current canvas.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -18,6 +18,7 @@
|
||||
- [x] Supoorts to export as `json`、`png`、`svg`、`pdf`、`markdown`、`xmind`, support import from `json`、`xmind`、`markdown`
|
||||
- [x] Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, and scrollbar
|
||||
- [x] Provide rich configurations to meet various scenarios and usage habits
|
||||
- [x] Support collaborative editing
|
||||
|
||||
## Repository Catalog Introduction
|
||||
|
||||
@@ -116,7 +117,7 @@ Unsupported: `IE` browser.
|
||||
|
||||
Open source is not easy. If this project is helpful to you, you can invite the author to have a cup of coffee~
|
||||
|
||||
> Please note the 【mind map】 for transfer. Your avatar and name will appear below.
|
||||
> Please note the 【mind map】 for transfer.
|
||||
|
||||
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
|
||||
|
||||
@@ -210,4 +211,16 @@ Open source is not easy. If this project is helpful to you, you can invite the a
|
||||
<img src="../../../../assets/avatar/沐风牧草.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>沐风牧草</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/有希.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>有希</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/樊笼.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>樊笼</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/达仁科技.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>达仁科技</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,16 +8,17 @@
|
||||
</blockquote>
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox15" checked="true" /><label for="checkbox15">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
|
||||
<li><input type="checkbox" id="checkbox16" checked="true" /><label for="checkbox16">Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
|
||||
<li><input type="checkbox" id="checkbox17" checked="true" /><label for="checkbox17">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox18" checked="true" /><label for="checkbox18">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
|
||||
<li><input type="checkbox" id="checkbox19" checked="true" /><label for="checkbox19">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, and fully customize node content using DDM</label></li>
|
||||
<li><input type="checkbox" id="checkbox20" checked="true" /><label for="checkbox20">Support canvas dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox21" checked="true" /><label for="checkbox21">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
|
||||
<li><input type="checkbox" id="checkbox22" checked="true" /><label for="checkbox22">Supoorts to export as </label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>, support import from <code>json</code>、<code>xmind</code>、<code>markdown</code></li>
|
||||
<li><input type="checkbox" id="checkbox23" checked="true" /><label for="checkbox23">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, and scrollbar</label></li>
|
||||
<li><input type="checkbox" id="checkbox24" checked="true" /><label for="checkbox24">Provide rich configurations to meet various scenarios and usage habits</label></li>
|
||||
<li><input type="checkbox" id="checkbox48" checked="true" /><label for="checkbox48">Pluggable architecture, in addition to core functions, other functions are provided as plugins, which can be used as needed to reduce packaging volume</label></li>
|
||||
<li><input type="checkbox" id="checkbox49" checked="true" /><label for="checkbox49">Support logical structure chart, mind map, Organizational chart, directory organization chart, timeline (horizontal and vertical), fishbone chart and other structures</label></li>
|
||||
<li><input type="checkbox" id="checkbox50" checked="true" /><label for="checkbox50">Built-in multiple themes, allowing for highly customizable styles, and supporting registration of new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox51" checked="true" /><label for="checkbox51">Node content supports text (regular text, rich text), images, icons, hyperlinks, notes, labels, summaries, and math formulas</label></li>
|
||||
<li><input type="checkbox" id="checkbox52" checked="true" /><label for="checkbox52">Nodes support drag and drop (drag and move, freely adjust), multiple node shapes, and fully customize node content using DDM</label></li>
|
||||
<li><input type="checkbox" id="checkbox53" checked="true" /><label for="checkbox53">Support canvas dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox54" checked="true" /><label for="checkbox54">Supports two multi node selection methods: mouse button drag selection and Ctrl+left button selection</label></li>
|
||||
<li><input type="checkbox" id="checkbox55" checked="true" /><label for="checkbox55">Supoorts to export as </label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>, support import from <code>json</code>、<code>xmind</code>、<code>markdown</code></li>
|
||||
<li><input type="checkbox" id="checkbox56" checked="true" /><label for="checkbox56">Support shortcut keys, forward and backward, correlation lines, search and replacement, small maps, watermarks, and scrollbar</label></li>
|
||||
<li><input type="checkbox" id="checkbox57" checked="true" /><label for="checkbox57">Provide rich configurations to meet various scenarios and usage habits</label></li>
|
||||
<li><input type="checkbox" id="checkbox58" checked="true" /><label for="checkbox58">Support collaborative editing</label></li>
|
||||
</ul>
|
||||
<h2>Repository Catalog Introduction</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
@@ -27,16 +28,16 @@ frameworks such as Vue and React, or without a framework.</p>
|
||||
<p>This is an online mind map built using the <code>simple-mind-map</code> library and based
|
||||
on <code>Vue2.x</code> and <code>ElementUI</code>. Features include:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox25" checked="true" /><label for="checkbox25">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
<li><input type="checkbox" id="checkbox59" checked="true" /><label for="checkbox59">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
images, icons, hyperlinks, notes, tags, and summaries</li>
|
||||
<li><input type="checkbox" id="checkbox26" checked="true" /><label for="checkbox26">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
<li><input type="checkbox" id="checkbox60" checked="true" /><label for="checkbox60">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
outline, theme selection, and structure selection</li>
|
||||
<li><input type="checkbox" id="checkbox27" checked="true" /><label for="checkbox27">Import and export functionality; data is saved in the browser's local</label>
|
||||
<li><input type="checkbox" id="checkbox61" checked="true" /><label for="checkbox61">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="checkbox28" checked="true" /><label for="checkbox28">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
<li><input type="checkbox" id="checkbox62" checked="true" /><label for="checkbox62">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
and organizing layout</li>
|
||||
<li><input type="checkbox" id="checkbox29" checked="true" /><label for="checkbox29">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
<li><input type="checkbox" id="checkbox63" checked="true" /><label for="checkbox63">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>
|
||||
@@ -77,7 +78,7 @@ full screen, support mini map</li>
|
||||
<h2>Invite the author to a cup of coffee</h2>
|
||||
<p>Open source is not easy. If this project is helpful to you, you can invite the author to have a cup of coffee~</p>
|
||||
<blockquote>
|
||||
<p>Please note the 【mind map】 for transfer. Your avatar and name will appear below.</p>
|
||||
<p>Please note the 【mind map】 for transfer.</p>
|
||||
</blockquote>
|
||||
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
|
||||
<img src="../../../../assets/img/wechat.jpg" style="width: 300px" />
|
||||
@@ -168,6 +169,18 @@ full screen, support mini map</li>
|
||||
<img src="../../../../assets/avatar/沐风牧草.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>沐风牧草</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/有希.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>有希</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/樊笼.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>樊笼</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/达仁科技.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>达仁科技</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,6 +15,12 @@ Gets the root node of the node tree
|
||||
|
||||
## Methods
|
||||
|
||||
### setData(data)
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
Dynamically set mind map data.
|
||||
|
||||
### clearActive()
|
||||
|
||||
Clears the currently active node
|
||||
|
||||
@@ -9,6 +9,11 @@ accessed through <code>mindMap.renderer</code>.</p>
|
||||
<h3>root</h3>
|
||||
<p>Gets the root node of the node tree</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>setData(data)</h3>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<p>Dynamically set mind map data.</p>
|
||||
<h3>clearActive()</h3>
|
||||
<p>Clears the currently active node</p>
|
||||
<h3>clearAllActive()</h3>
|
||||
|
||||
@@ -90,7 +90,9 @@ copyRenderTree({}, this.mindMap.renderer.renderTree);
|
||||
|
||||
- `removeActiveState`: `Boolean`, default is `false`, Whether to remove the active state of the node
|
||||
|
||||
- `keepId`: v0.4.6+, `Boolean`, default is `false`, Whether to retain the `id` of the replicated node will be deleted by default to prevent duplicate node `id`. However, for mobile node scenarios, the original `id` of the node needs to be retained
|
||||
- `removeId`:v0.7.3-fix.1+, Is remove the uid from the node data, default is `true`
|
||||
|
||||
> - `keepId`: (Original fourth parameter) v0.4.6+, `Boolean`, default is `false`, Whether to retain the `id` of the replicated node will be deleted by default to prevent duplicate node `id`. However, for mobile node scenarios, the original `id` of the node needs to be retained
|
||||
|
||||
Copy node tree data, mainly eliminating the reference `node` instance `_node`
|
||||
and copying the `data` of the data object, example:
|
||||
@@ -292,12 +294,14 @@ Focus and select all specified input boxes.
|
||||
|
||||
Adding additional data to the specified node list tree data will modify the original data.
|
||||
|
||||
#### createUidForAppointNodes(appointNodes)
|
||||
#### createUidForAppointNodes(appointNodes, createNewId)
|
||||
|
||||
> v0.7.2+
|
||||
|
||||
- `appointNodes`:Node instance list, array type.
|
||||
|
||||
- `createNewId`:v0.7.3-fix.1+, `Boolean`, default is `false`, If the node does not have a 'uid', a new 'uid' will be created. If 'true' is passed, a new 'uid' will be created regardless of whether the node data originally exists or not`
|
||||
|
||||
Adding a uid to the specified node list tree data (if the uid does not exist) will modify the original data.
|
||||
|
||||
#### getNodeIndex(node)
|
||||
@@ -351,6 +355,14 @@ Escape the incoming string, currently escaping the following three characters:
|
||||
|
||||
Generate colors based on incoming content, and the same content will generate the same color.
|
||||
|
||||
#### isSameObject(a, b)
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
- `a`、`b`: Object | Array, Two objects to compare
|
||||
|
||||
Determine whether two objects are the same, only handling objects or arrays.
|
||||
|
||||
## Simulate CSS background in Canvas
|
||||
|
||||
Import:
|
||||
|
||||
@@ -54,9 +54,14 @@ basic data, otherwise it will throw an error</p>
|
||||
<p><code>removeActiveState</code>: <code>Boolean</code>, default is <code>false</code>, Whether to remove the active state of the node</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>keepId</code>: v0.4.6+, <code>Boolean</code>, default is <code>false</code>, Whether to retain the <code>id</code> of the replicated node will be deleted by default to prevent duplicate node <code>id</code>. However, for mobile node scenarios, the original <code>id</code> of the node needs to be retained</p>
|
||||
<p><code>removeId</code>:v0.7.3-fix.1+, Is remove the uid from the node data, default is <code>true</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li><code>keepId</code>: (Original fourth parameter) v0.4.6+, <code>Boolean</code>, default is <code>false</code>, Whether to retain the <code>id</code> of the replicated node will be deleted by default to prevent duplicate node <code>id</code>. However, for mobile node scenarios, the original <code>id</code> of the node needs to be retained</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>Copy node tree data, mainly eliminating the reference <code>node</code> instance <code>_node</code>
|
||||
and copying the <code>data</code> of the data object, example:</p>
|
||||
<pre class="hljs"><code>copyNodeTree({}, node);
|
||||
@@ -222,12 +227,17 @@ and copying the <code>data</code> of the data object, example:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Adding additional data to the specified node list tree data will modify the original data.</p>
|
||||
<h4>createUidForAppointNodes(appointNodes)</h4>
|
||||
<h4>createUidForAppointNodes(appointNodes, createNewId)</h4>
|
||||
<blockquote>
|
||||
<p>v0.7.2+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>appointNodes</code>:Node instance list, array type.</li>
|
||||
<li>
|
||||
<p><code>appointNodes</code>:Node instance list, array type.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>createNewId</code>:v0.7.3-fix.1+, <code>Boolean</code>, default is <code>false</code>, If the node does not have a 'uid', a new 'uid' will be created. If 'true' is passed, a new 'uid' will be created regardless of whether the node data originally exists or not`</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Adding a uid to the specified node list tree data (if the uid does not exist) will modify the original data.</p>
|
||||
<h4>getNodeIndex(node)</h4>
|
||||
@@ -277,6 +287,14 @@ and copying the <code>data</code> of the data object, example:</p>
|
||||
<li><code>str</code>:String.</li>
|
||||
</ul>
|
||||
<p>Generate colors based on incoming content, and the same content will generate the same color.</p>
|
||||
<h4>isSameObject(a, b)</h4>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>a</code>、<code>b</code>: Object | Array, Two objects to compare</li>
|
||||
</ul>
|
||||
<p>Determine whether two objects are the same, only handling objects or arrays.</p>
|
||||
<h2>Simulate CSS background in Canvas</h2>
|
||||
<p>Import:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'</span>
|
||||
|
||||
@@ -57,6 +57,7 @@ export default [
|
||||
{ path: 'painter', title: 'Painter插件' },
|
||||
{ path: 'scrollbar', title: 'Scrollbar插件' },
|
||||
{ path: 'formula', title: 'Formula插件' },
|
||||
{ path: 'cooperate', title: 'Cooperate插件' },
|
||||
{ path: 'help1', title: '概要/关联线' },
|
||||
{ path: 'help2', title: '客户端' },
|
||||
{ path: 'help3', title: '打开预览在线文件' },
|
||||
@@ -96,6 +97,7 @@ export default [
|
||||
{ path: 'painter', title: 'Painter plugin' },
|
||||
{ path: 'scrollbar', title: 'Scrollbar plugin' },
|
||||
{ path: 'formula', title: 'Formula plugin' },
|
||||
{ path: 'cooperate', title: 'Cooperate plugin' },
|
||||
{ path: 'client', title: 'Client' }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
## 0.7.3-fix.2
|
||||
|
||||
修复协同编辑的一些问题:
|
||||
|
||||
1.插入同级节点时新节点位置不正确;
|
||||
|
||||
2.在同级节点中移动位置没有触发更新;
|
||||
|
||||
3.移动节点作为兄弟节点插入时位置不正确;
|
||||
|
||||
## 0.7.3-fix.1
|
||||
|
||||
修复:
|
||||
|
||||
> 1.修复一些情况下多选节点时的框选区域没有消失的问题。
|
||||
>
|
||||
> 2.修复多选节点时在节点上松开鼠标时框选区域不会消失的问题。
|
||||
>
|
||||
> 3.修复多次粘贴节点时由于节点uid重复造成的渲染异常问题。
|
||||
|
||||
Demo:
|
||||
|
||||
> 1.超链接输入框增加协议选择功能。
|
||||
|
||||
## 0.7.3
|
||||
|
||||
新增:1.新增协同编辑插件。
|
||||
|
||||
Demo:1.修复公式侧边栏组件导致的侧边栏自动关闭问题。
|
||||
|
||||
## 0.7.2
|
||||
|
||||
修复:
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.7.3-fix.2</h2>
|
||||
<p>修复协同编辑的一些问题:</p>
|
||||
<p>1.插入同级节点时新节点位置不正确;</p>
|
||||
<p>2.在同级节点中移动位置没有触发更新;</p>
|
||||
<p>3.移动节点作为兄弟节点插入时位置不正确;</p>
|
||||
<h2>0.7.3-fix.1</h2>
|
||||
<p>修复:</p>
|
||||
<blockquote>
|
||||
<p>1.修复一些情况下多选节点时的框选区域没有消失的问题。</p>
|
||||
<p>2.修复多选节点时在节点上松开鼠标时框选区域不会消失的问题。</p>
|
||||
<p>3.修复多次粘贴节点时由于节点uid重复造成的渲染异常问题。</p>
|
||||
</blockquote>
|
||||
<p>Demo:</p>
|
||||
<blockquote>
|
||||
<p>1.超链接输入框增加协议选择功能。</p>
|
||||
</blockquote>
|
||||
<h2>0.7.3</h2>
|
||||
<p>新增:1.新增协同编辑插件。</p>
|
||||
<p>Demo:1.修复公式侧边栏组件导致的侧边栏自动关闭问题。</p>
|
||||
<h2>0.7.2</h2>
|
||||
<p>修复:</p>
|
||||
<blockquote>
|
||||
|
||||
@@ -94,6 +94,7 @@ const mindMap = new MindMap({
|
||||
| dragPlaceholderRectFill(v0.7.2+) | String | | 节点拖拽时新位置的示意矩形的填充颜色,如果不传默认使用连线的颜色 |
|
||||
| dragOpacityConfig(v0.7.2+) | Object | { cloneNodeOpacity: 0.5, beingDragNodeOpacity: 0.3 } | 节点拖拽时的透明度配置,传递一个对象,字段含义分别为:跟随鼠标移动的克隆节点或矩形的透明度、被拖拽节点的透明度 |
|
||||
| tagsColorMap(v0.7.2+) | Object | {} | 自定义节点标签的颜色,可传一个对象,key为要指定颜色的标签内容,value为该标签内容的颜色,如果不传内部会根据标签内容生成对应的颜色 |
|
||||
| cooperateStyle(v0.7.3+) | Object | { avatarSize: 22, fontSize: 12 } | 节点协作编辑时的人员头像样式配置,字段含义分别为:头像大小、如果是文字头像,那么文字的大小 |
|
||||
|
||||
### 数据结构
|
||||
|
||||
@@ -307,6 +308,7 @@ mindMap.setTheme('主题名称')
|
||||
| svg_mouseleave(v0.5.1+) | 鼠标移出svg画布时触发 | e(事件对象) |
|
||||
| node_icon_click(v0.6.10+) | 点击节点内的图标时触发 | this(节点实例)、item(点击的图标名称)、e(事件对象) |
|
||||
| view_theme_change(v0.6.12+) | 调用了setTheme方法设置主题后触发 | theme(设置的新主题名称) |
|
||||
| set_data(v0.7.3+) | 调用了setData方法动态设置思维导图数据时触发 | data(新的思维导图数据) |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
|
||||
@@ -447,6 +447,12 @@
|
||||
<td>{}</td>
|
||||
<td>自定义节点标签的颜色,可传一个对象,key为要指定颜色的标签内容,value为该标签内容的颜色,如果不传内部会根据标签内容生成对应的颜色</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>cooperateStyle(v0.7.3+)</td>
|
||||
<td>Object</td>
|
||||
<td>{ avatarSize: 22, fontSize: 12 }</td>
|
||||
<td>节点协作编辑时的人员头像样式配置,字段含义分别为:头像大小、如果是文字头像,那么文字的大小</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>数据结构</h3>
|
||||
@@ -843,6 +849,11 @@ mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
<td>调用了setTheme方法设置主题后触发</td>
|
||||
<td>theme(设置的新主题名称)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set_data(v0.7.3+)</td>
|
||||
<td>调用了setData方法动态设置思维导图数据时触发</td>
|
||||
<td>data(新的思维导图数据)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
|
||||
124
web/src/pages/Doc/zh/cooperate/index.md
Normal file
124
web/src/pages/Doc/zh/cooperate/index.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Cooperate 插件 beta
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
该插件用于实现协同编辑。
|
||||
|
||||
## 介绍
|
||||
|
||||
该插件通过[Yjs](https://github.com/yjs/yjs)实现协同编辑,基本原理是将思维导图的树数据转成平级的对象数据,然后通过[Y.Map](https://docs.yjs.dev/api/shared-types/y.map)类型的共享数据进行协同,即当画布上进行了某些操作后会更新`y.map`对象,然后其他协同的客户端会接收到更新后的数据,再转换回树结构数据,更新画布即可实现实时更新。
|
||||
|
||||
要实现协同,后端是少不了的,`Yjs`提供了一些[Connection Provider](https://docs.yjs.dev/ecosystem/connection-provider)。同时也提供了后端的示例,但只是最简单的实现,实际项目中你应该需要重写或完善。
|
||||
|
||||
你可以选择适合自己的`Provider`,默认使用的是[y-webrtc](https://github.com/yjs/y-webrtc)。
|
||||
|
||||
## demo
|
||||
|
||||
如果你想通过demo来尝试一下可以通过以下步骤:
|
||||
|
||||
1. 克隆项目及安装依赖:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd mind-map
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
cd ..
|
||||
cd web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
```
|
||||
|
||||
2. 修改`web/src/pages/Edit/components/Edit.vue`文件
|
||||
|
||||
注册协同插件,即取消该行注释:
|
||||
|
||||
```js
|
||||
// .usePlugin(Cooperate)// 协同插件
|
||||
```
|
||||
|
||||
将信令服务器地址改为你本机的ip:
|
||||
|
||||
```js
|
||||
// cooperateTest 函数
|
||||
|
||||
signalingList: ['ws://【你的ip】:4444']
|
||||
```
|
||||
|
||||
3. 启动demo项目的本地服务:
|
||||
|
||||
```bash
|
||||
// web路径下执行
|
||||
npm run serve
|
||||
```
|
||||
|
||||
4. 启动信令服务器:
|
||||
|
||||
```bash
|
||||
// simple-mind-map路径下执行
|
||||
npm run wsServe
|
||||
```
|
||||
|
||||
该命令执行的是`simple-mind-map/bin/wsServer.mjs`文件,该文件的内容是从[y-webrtc](https://github.com/yjs/y-webrtc)仓库直接复制的,可能并不完善,请谨慎用于实际项目。
|
||||
|
||||
5. 在两个浏览器中访问服务地址:
|
||||
|
||||
```
|
||||
http://【你的ip】:8080/#/?userName=用户名
|
||||
```
|
||||
|
||||
你可以在不同的浏览器上设置不同的userName。然后就可以在一个浏览器中编辑,在另一个浏览器上看到自动更新了。
|
||||
|
||||
## 注册
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
||||
MindMap.usePlugin(Cooperate)
|
||||
```
|
||||
|
||||
注册完且实例化`MindMap`后可通过`mindMap.cooperate`获取到该实例。
|
||||
|
||||
## 方法
|
||||
|
||||
### getDoc()
|
||||
|
||||
获取Yjs doc实例。
|
||||
|
||||
### setProvider(provider, webrtcProviderConfig)
|
||||
|
||||
- `provider`:Yjs的连接提供者,可参考[Connection Provider](https://docs.yjs.dev/ecosystem/connection-provider),默认为`null`
|
||||
|
||||
- `webrtcProviderConfig`:webrtc provider的配置参数,需要传递一个对象,格式如下:
|
||||
|
||||
```js
|
||||
{
|
||||
roomName: '', // 必传,房间名称
|
||||
signalingList: [''],// 必传,指定信令服务器
|
||||
...// webrtc provider的其他配置
|
||||
}
|
||||
```
|
||||
|
||||
详细配置可参考[y-webrtc](https://github.com/yjs/y-webrtc)。
|
||||
|
||||
设置Yjs的连接提供者,`provider`如果不传,那么默认会使用`y-webrtc`,你也可以使用其他的`provider`。
|
||||
|
||||
如果使用默认的`y-webrtc`,那么需要通过第二个参数传入必要的配置。
|
||||
|
||||
`simple-mind-map/bin/wsServer.mjs`文件提供了一个简单的信令服务器代码,可供测试和参考。
|
||||
|
||||
### setUserInfo(userInfo)
|
||||
|
||||
- `userInfo`:用户信息。格式如下:
|
||||
|
||||
```js
|
||||
{
|
||||
id: '', // 必传,用户唯一的id
|
||||
name: '', // 用户名称。name和avatar两个只传一个即可,如果都传了,会显示avatar
|
||||
avatar: '', // 用户头像
|
||||
color: '' // 如果没有传头像,那么会以一个圆形来显示名称的第一个字,文字的颜色为白色,圆的颜色可以通过该字段设置
|
||||
}
|
||||
```
|
||||
|
||||
设置当前用户的信息,用于感知数据的同步和显示。即如果其他协同人员激活了某个节点时,会在你当前画布中的该节点上方显示他的头像。
|
||||
109
web/src/pages/Doc/zh/cooperate/index.vue
Normal file
109
web/src/pages/Doc/zh/cooperate/index.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Cooperate 插件 beta</h1>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<p>该插件用于实现协同编辑。</p>
|
||||
<h2>介绍</h2>
|
||||
<p>该插件通过<a href="https://github.com/yjs/yjs">Yjs</a>实现协同编辑,基本原理是将思维导图的树数据转成平级的对象数据,然后通过<a href="https://docs.yjs.dev/api/shared-types/y.map">Y.Map</a>类型的共享数据进行协同,即当画布上进行了某些操作后会更新<code>y.map</code>对象,然后其他协同的客户端会接收到更新后的数据,再转换回树结构数据,更新画布即可实现实时更新。</p>
|
||||
<p>要实现协同,后端是少不了的,<code>Yjs</code>提供了一些<a href="https://docs.yjs.dev/ecosystem/connection-provider">Connection Provider</a>。同时也提供了后端的示例,但只是最简单的实现,实际项目中你应该需要重写或完善。</p>
|
||||
<p>你可以选择适合自己的<code>Provider</code>,默认使用的是<a href="https://github.com/yjs/y-webrtc">y-webrtc</a>。</p>
|
||||
<h2>demo</h2>
|
||||
<p>如果你想通过demo来尝试一下可以通过以下步骤:</p>
|
||||
<ol>
|
||||
<li>克隆项目及安装依赖:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>git <span class="hljs-built_in">clone</span> https://github.com/wanglin2/mind-map.git
|
||||
<span class="hljs-built_in">cd</span> mind-map
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
<span class="hljs-built_in">cd</span> ..
|
||||
<span class="hljs-built_in">cd</span> web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
</code></pre>
|
||||
<ol start="2">
|
||||
<li>修改<code>web/src/pages/Edit/components/Edit.vue</code>文件</li>
|
||||
</ol>
|
||||
<p>注册协同插件,即取消该行注释:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// .usePlugin(Cooperate)// 协同插件</span>
|
||||
</code></pre>
|
||||
<p>将信令服务器地址改为你本机的ip:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// cooperateTest 函数</span>
|
||||
|
||||
<span class="hljs-attr">signalingList</span>: [<span class="hljs-string">'ws://【你的ip】:4444'</span>]
|
||||
</code></pre>
|
||||
<ol start="3">
|
||||
<li>启动demo项目的本地服务:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>// web路径下执行
|
||||
npm run serve
|
||||
</code></pre>
|
||||
<ol start="4">
|
||||
<li>启动信令服务器:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>// simple-mind-map路径下执行
|
||||
npm run wsServe
|
||||
</code></pre>
|
||||
<p>该命令执行的是<code>simple-mind-map/bin/wsServer.mjs</code>文件,该文件的内容是从<a href="https://github.com/yjs/y-webrtc">y-webrtc</a>仓库直接复制的,可能并不完善,请谨慎用于实际项目。</p>
|
||||
<ol start="5">
|
||||
<li>在两个浏览器中访问服务地址:</li>
|
||||
</ol>
|
||||
<pre class="hljs"><code>http://【你的ip】:8080/#/?userName=用户名
|
||||
</code></pre>
|
||||
<p>你可以在不同的浏览器上设置不同的userName。然后就可以在一个浏览器中编辑,在另一个浏览器上看到自动更新了。</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> Cooperate <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/plugins/Cooperate.js'</span>
|
||||
MindMap.usePlugin(Cooperate)
|
||||
</code></pre>
|
||||
<p>注册完且实例化<code>MindMap</code>后可通过<code>mindMap.cooperate</code>获取到该实例。</p>
|
||||
<h2>方法</h2>
|
||||
<h3>getDoc()</h3>
|
||||
<p>获取Yjs doc实例。</p>
|
||||
<h3>setProvider(provider, webrtcProviderConfig)</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>provider</code>:Yjs的连接提供者,可参考<a href="https://docs.yjs.dev/ecosystem/connection-provider">Connection Provider</a>,默认为<code>null</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>webrtcProviderConfig</code>:webrtc provider的配置参数,需要传递一个对象,格式如下:</p>
|
||||
</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">roomName</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// 必传,房间名称 </span>
|
||||
<span class="hljs-attr">signalingList</span>: [<span class="hljs-string">''</span>],<span class="hljs-comment">// 必传,指定信令服务器</span>
|
||||
...<span class="hljs-comment">// webrtc provider的其他配置</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>详细配置可参考<a href="https://github.com/yjs/y-webrtc">y-webrtc</a>。</p>
|
||||
<p>设置Yjs的连接提供者,<code>provider</code>如果不传,那么默认会使用<code>y-webrtc</code>,你也可以使用其他的<code>provider</code>。</p>
|
||||
<p>如果使用默认的<code>y-webrtc</code>,那么需要通过第二个参数传入必要的配置。</p>
|
||||
<p><code>simple-mind-map/bin/wsServer.mjs</code>文件提供了一个简单的信令服务器代码,可供测试和参考。</p>
|
||||
<h3>setUserInfo(userInfo)</h3>
|
||||
<ul>
|
||||
<li><code>userInfo</code>:用户信息。格式如下:</li>
|
||||
</ul>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">id</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// 必传,用户唯一的id</span>
|
||||
<span class="hljs-attr">name</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// 用户名称。name和avatar两个只传一个即可,如果都传了,会显示avatar</span>
|
||||
<span class="hljs-attr">avatar</span>: <span class="hljs-string">''</span>, <span class="hljs-comment">// 用户头像</span>
|
||||
<span class="hljs-attr">color</span>: <span class="hljs-string">''</span> <span class="hljs-comment">// 如果没有传头像,那么会以一个圆形来显示名称的第一个字,文字的颜色为白色,圆的颜色可以通过该字段设置</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>设置当前用户的信息,用于感知数据的同步和显示。即如果其他协同人员激活了某个节点时,会在你当前画布中的该节点上方显示他的头像。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## 插入子节点
|
||||
|
||||
插入子节点很节点,执行`INSERT_CHILD_NODE`命令即可:
|
||||
插入子节点很简单,执行`INSERT_CHILD_NODE`命令即可:
|
||||
|
||||
```js
|
||||
mindMap.execCommand('INSERT_CHILD_NODE')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<h1>插入/删除节点、前进回退</h1>
|
||||
<p>首先和操作节点内容一样,也需要监听节点的激活事件,然后禁用相关按钮。</p>
|
||||
<h2>插入子节点</h2>
|
||||
<p>插入子节点很节点,执行<code>INSERT_CHILD_NODE</code>命令即可:</p>
|
||||
<p>插入子节点很简单,执行<code>INSERT_CHILD_NODE</code>命令即可:</p>
|
||||
<pre class="hljs"><code>mindMap.execCommand(<span class="hljs-string">'INSERT_CHILD_NODE'</span>)
|
||||
</code></pre>
|
||||
<p>这样就会在当前激活节点(如果存在多个激活节点,默认会操作第一个激活节点)下添加一个子节点。</p>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
- [x] 支持导出为`json`、`png`、`svg`、`pdf`、`markdown`、`xmind`,支持从`json`、`xmind`、`markdown`导入
|
||||
- [x] 支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条
|
||||
- [x] 提供丰富的配置,满足各种场景各种使用习惯
|
||||
- [x] 支持协同编辑
|
||||
|
||||
## 仓库目录介绍
|
||||
|
||||
@@ -105,11 +106,11 @@
|
||||
|
||||
## 请作者喝杯咖啡
|
||||
|
||||
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡哟~
|
||||
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~
|
||||
|
||||
> 厚椰乳一盒 + 纯牛奶半盒 + 冰块 + 咖啡液 = 生椰拿铁 yyds
|
||||
|
||||
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。你的头像和名字将会出现在下面。
|
||||
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。
|
||||
|
||||
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
|
||||
|
||||
@@ -203,4 +204,16 @@
|
||||
<img src="../../../../assets/avatar/沐风牧草.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>沐风牧草</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/有希.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>有希</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/樊笼.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>樊笼</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/达仁科技.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>达仁科技</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,16 +8,17 @@
|
||||
</blockquote>
|
||||
<h2>特性</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox0" checked="true" /><label for="checkbox0">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox1" checked="true" /><label for="checkbox1">支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox2" checked="true" /><label for="checkbox2">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox3" checked="true" /><label for="checkbox3">节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式</label></li>
|
||||
<li><input type="checkbox" id="checkbox4" checked="true" /><label for="checkbox4">节点支持拖拽(拖拽移动、自由调整)、多种节点形状,支持使用 DDM 完全自定义节点内容</label></li>
|
||||
<li><input type="checkbox" id="checkbox5" checked="true" /><label for="checkbox5">支持画布拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox6" checked="true" /><label for="checkbox6">支持鼠标按键拖动选择和Ctrl+左键两种多选节点方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox7" checked="true" /><label for="checkbox7">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox8" checked="true" /><label for="checkbox8">支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条</label></li>
|
||||
<li><input type="checkbox" id="checkbox9" checked="true" /><label for="checkbox9">提供丰富的配置,满足各种场景各种使用习惯</label></li>
|
||||
<li><input type="checkbox" id="checkbox32" checked="true" /><label for="checkbox32">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox33" checked="true" /><label for="checkbox33">支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴(横向、竖向)、鱼骨图等结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox34" checked="true" /><label for="checkbox34">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox35" checked="true" /><label for="checkbox35">节点内容支持文本(普通文本、富文本)、图片、图标、超链接、备注、标签、概要、数学公式</label></li>
|
||||
<li><input type="checkbox" id="checkbox36" checked="true" /><label for="checkbox36">节点支持拖拽(拖拽移动、自由调整)、多种节点形状,支持使用 DDM 完全自定义节点内容</label></li>
|
||||
<li><input type="checkbox" id="checkbox37" checked="true" /><label for="checkbox37">支持画布拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox38" checked="true" /><label for="checkbox38">支持鼠标按键拖动选择和Ctrl+左键两种多选节点方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox39" checked="true" /><label for="checkbox39">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>、<code>xmind</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox40" checked="true" /><label for="checkbox40">支持快捷键、前进后退、关联线、搜索替换、小地图、水印、滚动条</label></li>
|
||||
<li><input type="checkbox" id="checkbox41" checked="true" /><label for="checkbox41">提供丰富的配置,满足各种场景各种使用习惯</label></li>
|
||||
<li><input type="checkbox" id="checkbox42" checked="true" /><label for="checkbox42">支持协同编辑</label></li>
|
||||
</ul>
|
||||
<h2>仓库目录介绍</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
@@ -25,11 +26,11 @@
|
||||
<p>2.<code>web</code></p>
|
||||
<p>使用<code>simple-mind-map</code>库,基于<code>vue2.x</code>、<code>ElementUI</code>搭建的在线思维导图。特性:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox10" checked="true" /><label for="checkbox10">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox11" checked="true" /><label for="checkbox11">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox12" checked="true" /><label for="checkbox12">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox13" checked="true" /><label for="checkbox13">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox14" checked="true" /><label for="checkbox14">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
<li><input type="checkbox" id="checkbox43" checked="true" /><label for="checkbox43">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox44" checked="true" /><label for="checkbox44">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox45" checked="true" /><label for="checkbox45">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox46" checked="true" /><label for="checkbox46">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox47" checked="true" /><label for="checkbox47">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
</ul>
|
||||
<p>提供文档页面服务。</p>
|
||||
<p>3.<code>dist</code></p>
|
||||
@@ -66,12 +67,12 @@
|
||||
<h2>License</h2>
|
||||
<p><a href="https://opensource.org/licenses/MIT">MIT</a></p>
|
||||
<h2>请作者喝杯咖啡</h2>
|
||||
<p>开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡哟~</p>
|
||||
<p>开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~</p>
|
||||
<blockquote>
|
||||
<p>厚椰乳一盒 + 纯牛奶半盒 + 冰块 + 咖啡液 = 生椰拿铁 yyds</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。你的头像和名字将会出现在下面。</p>
|
||||
<p>推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。</p>
|
||||
</blockquote>
|
||||
<img src="../../../../assets/img/alipay.jpg" style="width: 300px" />
|
||||
<img src="../../../../assets/img/wechat.jpg" style="width: 300px" />
|
||||
@@ -162,6 +163,18 @@
|
||||
<img src="../../../../assets/avatar/沐风牧草.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>沐风牧草</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/有希.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>有希</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/樊笼.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>樊笼</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px;">
|
||||
<img src="../../../../assets/avatar/达仁科技.jpg" style="width: 50px;height: 50px;object-fit: cover;border-radius: 50%;" />
|
||||
<p>达仁科技</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
|
||||
## 方法
|
||||
|
||||
### setData(data)
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
动态设置思维导图数据。
|
||||
|
||||
### clearActive()
|
||||
|
||||
清除当前激活的节点
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
<h3>root</h3>
|
||||
<p>获取节点树的根节点</p>
|
||||
<h2>方法</h2>
|
||||
<h3>setData(data)</h3>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<p>动态设置思维导图数据。</p>
|
||||
<h3>clearActive()</h3>
|
||||
<p>清除当前激活的节点</p>
|
||||
<h3>clearAllActive()</h3>
|
||||
|
||||
@@ -82,11 +82,13 @@ walk(tree, null, () => {}, () => {}, false, 0, 0)
|
||||
copyRenderTree({}, this.mindMap.renderer.renderTree)
|
||||
```
|
||||
|
||||
#### copyNodeTree(tree, root, removeActiveState, keepId)
|
||||
#### copyNodeTree(tree, root, removeActiveState, removeId)
|
||||
|
||||
- `removeActiveState`:`Boolean`,默认为`false`,是否移除节点的激活状态
|
||||
|
||||
- `keepId`:v0.4.6+,`Boolean`,默认为`false`,是否保留被复制节点的`id`,默认会删除`id`防止节点`id`重复,但是对于移动节点的场景,节点原`id`需要保留
|
||||
- `removeId`:v0.7.3-fix.1+,是否移除节点数据中的uid,默认为`true`
|
||||
|
||||
> - `keepId`: (原第四个参数)`Boolean`,默认为`false`,是否保留被复制节点的`id`,默认会删除`id`防止节点`id`重复,但是对于移动节点的场景,节点原`id`需要保留。
|
||||
|
||||
复制节点树数据,主要是剔除其中的引用`node`实例的`_node`,然后复制`data`对象的数据,示例:
|
||||
|
||||
@@ -287,12 +289,14 @@ copyNodeTree({}, node)
|
||||
|
||||
给指定的节点列表树数据添加附加数据,会修改原数据。
|
||||
|
||||
#### createUidForAppointNodes(appointNodes)
|
||||
#### createUidForAppointNodes(appointNodes, createNewId)
|
||||
|
||||
> v0.7.2+
|
||||
|
||||
- `appointNodes`:节点实例列表,数组类型。
|
||||
|
||||
- `createNewId`:v0.7.3-fix.1+,`Boolean`,默认为`false`,即如果节点不存在`uid`的话,会创建新的`uid`。如果传`true`,那么无论节点数据原来是否存在`uid`,都会创建新的`uid`
|
||||
|
||||
给指定的节点列表树数据添加uid(如果uid不存在的话),会修改原数据。
|
||||
|
||||
#### getNodeIndex(node)
|
||||
@@ -346,6 +350,14 @@ copyNodeTree({}, node)
|
||||
> -> >
|
||||
```
|
||||
|
||||
#### isSameObject(a, b)
|
||||
|
||||
> v0.7.3+
|
||||
|
||||
- `a`、`b`:Object | Array, 要进行对比的两个对象
|
||||
|
||||
判断两个对象是否相同,只处理对象或数组。
|
||||
|
||||
## 在canvas中模拟css的背景属性
|
||||
|
||||
引入:
|
||||
|
||||
@@ -44,15 +44,20 @@
|
||||
<p>复制渲染树数据,示例:</p>
|
||||
<pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree)
|
||||
</code></pre>
|
||||
<h4>copyNodeTree(tree, root, removeActiveState, keepId)</h4>
|
||||
<h4>copyNodeTree(tree, root, removeActiveState, removeId)</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>removeActiveState</code>:<code>Boolean</code>,默认为<code>false</code>,是否移除节点的激活状态</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>keepId</code>:v0.4.6+,<code>Boolean</code>,默认为<code>false</code>,是否保留被复制节点的<code>id</code>,默认会删除<code>id</code>防止节点<code>id</code>重复,但是对于移动节点的场景,节点原<code>id</code>需要保留</p>
|
||||
<p><code>removeId</code>:v0.7.3-fix.1+,是否移除节点数据中的uid,默认为<code>true</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li><code>keepId</code>: (原第四个参数)<code>Boolean</code>,默认为<code>false</code>,是否保留被复制节点的<code>id</code>,默认会删除<code>id</code>防止节点<code>id</code>重复,但是对于移动节点的场景,节点原<code>id</code>需要保留。</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>复制节点树数据,主要是剔除其中的引用<code>node</code>实例的<code>_node</code>,然后复制<code>data</code>对象的数据,示例:</p>
|
||||
<pre class="hljs"><code>copyNodeTree({}, node)
|
||||
</code></pre>
|
||||
@@ -217,12 +222,17 @@
|
||||
</li>
|
||||
</ul>
|
||||
<p>给指定的节点列表树数据添加附加数据,会修改原数据。</p>
|
||||
<h4>createUidForAppointNodes(appointNodes)</h4>
|
||||
<h4>createUidForAppointNodes(appointNodes, createNewId)</h4>
|
||||
<blockquote>
|
||||
<p>v0.7.2+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>appointNodes</code>:节点实例列表,数组类型。</li>
|
||||
<li>
|
||||
<p><code>appointNodes</code>:节点实例列表,数组类型。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>createNewId</code>:v0.7.3-fix.1+,<code>Boolean</code>,默认为<code>false</code>,即如果节点不存在<code>uid</code>的话,会创建新的<code>uid</code>。如果传<code>true</code>,那么无论节点数据原来是否存在<code>uid</code>,都会创建新的<code>uid</code></p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>给指定的节点列表树数据添加uid(如果uid不存在的话),会修改原数据。</p>
|
||||
<h4>getNodeIndex(node)</h4>
|
||||
@@ -272,6 +282,14 @@
|
||||
< -> &lt;
|
||||
> -> &gt;
|
||||
</code></pre>
|
||||
<h4>isSameObject(a, b)</h4>
|
||||
<blockquote>
|
||||
<p>v0.7.3+</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><code>a</code>、<code>b</code>:Object | Array, 要进行对比的两个对象</li>
|
||||
</ul>
|
||||
<p>判断两个对象是否相同,只处理对象或数组。</p>
|
||||
<h2>在canvas中模拟css的背景属性</h2>
|
||||
<p>引入:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'</span>
|
||||
|
||||
@@ -45,6 +45,7 @@ import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
|
||||
import Painter from 'simple-mind-map/src/plugins/Painter.js'
|
||||
import ScrollbarPlugin from 'simple-mind-map/src/plugins/Scrollbar.js'
|
||||
import Formula from 'simple-mind-map/src/plugins/Formula.js'
|
||||
import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
||||
import OutlineSidebar from './OutlineSidebar'
|
||||
import Style from './Style'
|
||||
import BaseStyle from './BaseStyle'
|
||||
@@ -95,6 +96,7 @@ MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Painter)
|
||||
.usePlugin(ScrollbarPlugin)
|
||||
.usePlugin(Formula)
|
||||
// .usePlugin(Cooperate)// 协同插件
|
||||
|
||||
// 注册自定义主题
|
||||
customThemeList.forEach(item => {
|
||||
@@ -387,6 +389,8 @@ export default {
|
||||
if (hasFileURL) {
|
||||
this.$bus.$emit('handle_file_url')
|
||||
}
|
||||
// 协同测试
|
||||
this.cooperateTest()
|
||||
},
|
||||
|
||||
// url中是否存在要打开的文件
|
||||
@@ -476,13 +480,13 @@ export default {
|
||||
|
||||
// 测试动态插入节点
|
||||
testDynamicCreateNodes() {
|
||||
return
|
||||
// return
|
||||
setTimeout(() => {
|
||||
// 动态给指定节点添加子节点
|
||||
// this.mindMap.execCommand(
|
||||
// 'INSERT_CHILD_NODE',
|
||||
// false,
|
||||
// this.mindMap.renderer.root,
|
||||
// null,
|
||||
// {
|
||||
// text: '自定义内容'
|
||||
// },
|
||||
@@ -579,6 +583,24 @@ export default {
|
||||
// 动态删除指定节点
|
||||
// this.mindMap.execCommand('REMOVE_NODE', this.mindMap.renderer.root.children[0])
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 协同测试
|
||||
cooperateTest() {
|
||||
if (this.mindMap.cooperate && this.$route.query.userName) {
|
||||
this.mindMap.cooperate.setProvider(null, {
|
||||
roomName: 'demo-room',
|
||||
signalingList: ['ws://192.168.3.125:4444']
|
||||
})
|
||||
this.mindMap.cooperate.setUserInfo({
|
||||
id: Math.random(),
|
||||
name: this.$route.query.userName,
|
||||
color: ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399'][
|
||||
Math.floor(Math.random() * 5)
|
||||
],
|
||||
avatar: Math.random() > 0.5 ? 'https://img0.baidu.com/it/u=4270674549,2416627993&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1696006800&t=4d32871d14a7224a4591d0c3c7a97311' : ''
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,14 @@
|
||||
placeholder="http://xxxx.com/"
|
||||
@keyup.native.stop
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
@blur="handleUrl()"
|
||||
>
|
||||
<el-select v-model="protocol" slot="prepend" style="width: 80px;">
|
||||
<el-option label="https" value="https"></el-option>
|
||||
<el-option label="http" value="http"></el-option>
|
||||
<el-option label="无" value="none"></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="name">{{ $t('nodeHyperlink.name') }}</span>
|
||||
@@ -46,7 +53,8 @@ export default {
|
||||
dialogVisible: false,
|
||||
link: '',
|
||||
linkTitle: '',
|
||||
activeNodes: []
|
||||
activeNodes: [],
|
||||
protocol: 'https'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -63,6 +71,7 @@ export default {
|
||||
if (this.activeNodes.length > 0) {
|
||||
let firstNode = this.activeNodes[0]
|
||||
this.link = firstNode.getData('hyperlink')
|
||||
this.handleUrl(true)
|
||||
this.linkTitle = firstNode.getData('hyperlinkTitle')
|
||||
} else {
|
||||
this.link = ''
|
||||
@@ -70,6 +79,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
removeProtocol(url) {
|
||||
return url.replace(/^https?:\/\//, '')
|
||||
},
|
||||
|
||||
handleUrl(setProtocolNoneIfNotExist) {
|
||||
const res = this.link.match(/^(https?):\/\//)
|
||||
if (res && res[1]) {
|
||||
this.protocol = res[1]
|
||||
} else if (!this.link) {
|
||||
this.protocol = 'https'
|
||||
} else if (setProtocolNoneIfNotExist) {
|
||||
this.protocol = 'none'
|
||||
}
|
||||
this.link = this.removeProtocol(this.link)
|
||||
},
|
||||
|
||||
handleShowNodeLink() {
|
||||
this.activeNodes[0].mindMap.keyCommand.pause()
|
||||
this.$bus.$emit('startTextEdit')
|
||||
@@ -94,7 +119,10 @@ export default {
|
||||
*/
|
||||
confirm() {
|
||||
this.activeNodes.forEach(node => {
|
||||
node.setHyperlink(this.link, this.linkTitle)
|
||||
node.setHyperlink(
|
||||
(this.protocol === 'none' ? '' : this.protocol + '://') + this.link,
|
||||
this.linkTitle
|
||||
)
|
||||
this.cancel()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,15 +42,15 @@ export default {
|
||||
dataList: [
|
||||
{
|
||||
icon: 'iconstar',
|
||||
value: 'Github star数量800+'
|
||||
value: 'Github star数量1000+'
|
||||
},
|
||||
{
|
||||
icon: 'iconfork',
|
||||
value: 'Github fork数量150+'
|
||||
value: 'Github fork数量200+'
|
||||
},
|
||||
{
|
||||
icon: 'iconxiazai',
|
||||
value: 'npm总下载次数15000+'
|
||||
value: 'npm总下载次数20000+'
|
||||
},
|
||||
{
|
||||
icon: 'iconteamwork',
|
||||
|
||||
Reference in New Issue
Block a user