diff --git a/simple-mind-map/src/plugins/Cooperate.js b/simple-mind-map/src/plugins/Cooperate.js index 877a4cdc..d72377ab 100644 --- a/simple-mind-map/src/plugins/Cooperate.js +++ b/simple-mind-map/src/plugins/Cooperate.js @@ -7,33 +7,70 @@ class Cooperate { constructor(opt) { this.opt = opt this.mindMap = opt.mindMap + // yjs文档 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.awareness = this.provider.awareness - this.currentData = null - this.userInfo = null + // 共享数据 + this.ymap = null + // 连接提供者 + this.provider = null + // 感知数据 + this.awareness = null this.currentAwarenessData = [] - - // 处理数据 - 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.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.onObserve = this.onObserve.bind(this) - this.ymap.observe(this.onObserve) - // 监听思维导图改变 this.onDataChange = this.onDataChange.bind(this) this.mindMap.on('data_change', this.onDataChange) @@ -42,31 +79,33 @@ class Cooperate { this.onNodeActive = this.onNodeActive.bind(this) this.mindMap.on('node_active', this.onNodeActive) - // 监听状态同步事件 - this.onAwareness = this.onAwareness.bind(this) - this.awareness.on('change', this.onAwareness) + // 监听设置思维导图数据事件 + this.initData = this.initData.bind(this) + this.mindMap.on('set_data', this.initData) } // 解绑事件 unBindEvent() { - this.ymap.unobserve(this.onObserve) + 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 - if (this.mindMap.richText) { - this.mindMap.renderer.renderTree = - this.mindMap.richText.handleSetData(res) - } else { - this.mindMap.renderer.renderTree = res - } + // 更新思维导图画布 + this.mindMap.renderer.setData(res) this.mindMap.render() this.mindMap.command.addHistory() } @@ -77,16 +116,37 @@ class Cooperate { 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 => { - // 当前激活的节点id列表 return item.uid }) }) @@ -112,7 +172,7 @@ class Cooperate { this.userInfo = userInfo || null } - // 监听状态同步事件 + // 监听感知数据同步事件 onAwareness() { const walk = (list, callback) => { list.forEach(value => { @@ -129,11 +189,11 @@ class Cooperate { }) }) } - // 清除之前的状态 + // 清除之前的数据 walk(this.currentAwarenessData, (node, userInfo) => { node.removeUser(userInfo) }) - // 设置当前状态 + // 设置当前数据 const data = Array.from(this.awareness.getStates().values()) this.currentAwarenessData = data walk(data, (node, userInfo) => { @@ -246,27 +306,6 @@ class Cooperate { 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() diff --git a/web/src/pages/Edit/components/Edit.vue b/web/src/pages/Edit/components/Edit.vue index 480b701c..5696a551 100644 --- a/web/src/pages/Edit/components/Edit.vue +++ b/web/src/pages/Edit/components/Edit.vue @@ -96,7 +96,7 @@ MindMap.usePlugin(MiniMap) .usePlugin(Painter) .usePlugin(ScrollbarPlugin) .usePlugin(Formula) - .usePlugin(Cooperate) + // .usePlugin(Cooperate)// 协同插件 // 注册自定义主题 customThemeList.forEach(item => { @@ -389,16 +389,8 @@ export default { if (hasFileURL) { this.$bus.$emit('handle_file_url') } - if (this.$route.query.userName) { - 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' : '' - }) - } + // 协同测试 + this.cooperateTest() }, // url中是否存在要打开的文件 @@ -591,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' : '' + }) + } } } }