Newer
Older
import uuidv4 from "uuid/v4"
import yArray from "y-array"
import yMap from "y-map"
import yMemory from "y-memory"
import Y from "yjs"
import yWebrtc from "./y-webrtc/index.js"
yMemory(Y)
yMap(Y)
yArray(Y)
yWebrtc(Y)
class Room extends EventTarget {
constructor(name) {
super()
this.name = name
this._y = null
this.ownID = null
}
disconnect() {
this._y.destroy()
}
this._y.share.strokeAdd.set(id, Y.Array).push([[x, y, w]])
extendPath(id, [x, y, w]) {
this._y.share.strokeAdd.get(id).push([[x, y, w]])
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
}
getPaths() {
let paths = new Map()
for (let id of this._y.share.strokeAdd.keys()) {
paths.set(id, this._generatePath(id))
}
return paths
}
erasePoint(id, idx) {
let eraseSet = this._y.share.strokeErase.get(id)
if (!eraseSet) {
eraseSet = this._y.share.strokeErase.set(id, Y.Map)
}
eraseSet.set(idx.toString(), true)
}
// Generate an array of points [x, y, exist] by merging the path's add and erase sets
_generatePath(id) {
let addSet = this._y.share.strokeAdd.get(id)
if (addSet === undefined) {
return []
}
let eraseSet = this._y.share.strokeErase.get(id) || { get: () => false }
return addSet
.toArray()
.map((p = [], i) => [p[0], p[1], p[2], !eraseSet.get(i.toString())])
}
inviteUser(id) {
this._y.connector.connectToPeer(id)
}
async _initialise() {
this._y = await Y({
db: {
name: "memory",
},
connector: {
name: "webrtc",
url: "/",
room: this.name,
onUserEvent: (event) => {
if (event.action == "userID") {
const { id } = event
this.ownID = id
this.dispatchEvent(new CustomEvent("allocateOwnID", { detail: id }))
} else if (event.action == "userJoined") {
const { user: id } = event
this.dispatchEvent(new CustomEvent("userJoin", { detail: id }))
} else if (event.action == "userLeft") {
const { user: id } = event
this.dispatchEvent(new CustomEvent("userLeave", { detail: id }))
}
},
},
share: {
strokeAdd: "Map",
strokeErase: "Map",
this._y.share.strokeAdd.observe((lineEvent) => {
const points = this._generatePath(lineEvent.name)
const detail = { id: lineEvent.name, points }
this.dispatchEvent(new CustomEvent("addOrUpdatePath", { detail }))
lineEvent.value.observe((pointEvent) => {
if (pointEvent.type == "insert") {
const points = this._generatePath(lineEvent.name)
const detail = { id: lineEvent.name, points }
this.dispatchEvent(new CustomEvent("addOrUpdatePath", { detail }))
}
})
}
})
this._y.share.strokeErase.observe((lineEvent) => {
if (lineEvent.type == "add") {
const points = this._generatePath(lineEvent.name)
const detail = { id: lineEvent.name, points }
this.dispatchEvent(new CustomEvent("addOrUpdatePath", { detail }))
lineEvent.value.observe((pointEvent) => {
if (pointEvent.type == "add") {
const points = this._generatePath(lineEvent.name)
const detail = { id: lineEvent.name, points }
this.dispatchEvent(new CustomEvent("addOrUpdatePath", { detail }))
}
})
}
})
}
}
export const connect = async (roomName) => {
const room = new Room(roomName)
await room._initialise()
return room
}