mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-21 18:37:43 +08:00
207 lines
4.8 KiB
JavaScript
207 lines
4.8 KiB
JavaScript
import * as Y from 'yjs'
|
|
import { WebrtcProvider } from 'y-webrtc'
|
|
import { isSameObject, simpleDeepClone } from '../utils/index'
|
|
|
|
// 协同插件
|
|
class Cooperate {
|
|
constructor(opt) {
|
|
this.opt = opt
|
|
this.mindMap = opt.mindMap
|
|
this.ydoc = new Y.Doc()
|
|
this.ymap = this.ydoc.getMap()
|
|
this.provider = new WebrtcProvider('demo-room', this.ydoc, {
|
|
signaling: ['ws://10.16.83.11:4444']
|
|
})
|
|
this.currentData = null
|
|
|
|
// 处理数据
|
|
if (this.mindMap.opt.data) {
|
|
this.currentData = this.transformTreeDataToObject(this.mindMap.opt.data)
|
|
Object.keys(this.currentData).forEach(uid => {
|
|
this.ymap.set(uid, this.currentData[uid])
|
|
})
|
|
}
|
|
|
|
this.bindEvent()
|
|
}
|
|
|
|
// 绑定事件
|
|
bindEvent() {
|
|
// 监听数据同步
|
|
this.onObserve = this.onObserve.bind(this)
|
|
this.ymap.observe(this.onObserve)
|
|
|
|
// 监听思维导图改变
|
|
this.onDataChange = this.onDataChange.bind(this)
|
|
this.mindMap.on('data_change', this.onDataChange)
|
|
}
|
|
|
|
// 解绑事件
|
|
unBindEvent() {
|
|
this.ymap.unobserve(this.onObserve)
|
|
this.mindMap.off('data_change', this.onDataChange)
|
|
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
|
|
if (this.mindMap.richText) {
|
|
this.mindMap.renderer.renderTree =
|
|
this.mindMap.richText.handleSetData(res)
|
|
} else {
|
|
this.mindMap.renderer.renderTree = res
|
|
}
|
|
this.mindMap.render()
|
|
this.mindMap.command.addHistory()
|
|
}
|
|
|
|
// 当前思维导图改变后的处理,触发同步
|
|
onDataChange(data) {
|
|
const res = this.transformTreeDataToObject(data)
|
|
this.updateChanges(res)
|
|
}
|
|
|
|
// 将树结构转平级对象
|
|
/*
|
|
{
|
|
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) {
|
|
if (map[parentUid]) {
|
|
map[parentUid].children.push(node)
|
|
} else {
|
|
map[parentUid] = {
|
|
data: simpleDeepClone(data[parentUid].data),
|
|
children: [node]
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return 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)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// 插件被移除前做的事情
|
|
beforePluginRemove() {
|
|
this.unBindEvent()
|
|
}
|
|
|
|
// 插件被卸载前做的事情
|
|
beforePluginDestroy() {
|
|
this.unBindEvent()
|
|
}
|
|
}
|
|
|
|
Cooperate.instanceName = 'cooperate'
|
|
|
|
export default Cooperate
|