mind-map/simple-mind-map/src/plugins/Cooperate.js
2023-09-27 18:21:27 +08:00

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