js-draw icon indicating copy to clipboard operation
js-draw copied to clipboard

Efficient interface when combined with CRDT

Open satoren opened this issue 10 months ago • 4 comments

Thank you for publishing such an interesting library.

I have created a sample collaborative editing feature by combining your js-draw with Yjs. https://y-phoenix.gigalixirapp.com/js-draw

As you can see from the source code, the current method of obtaining differences is very inefficient.

To achieve this more efficiently, I need a way to determine the changes made when a user edits.

Additionally, I need a method to override the handlers for Undo/Redo so that they work on a per-user basis.

Thank you.

satoren avatar Feb 07 '25 12:02 satoren

Thank you for your interest in js-draw!

Would it be possible to serialize commands instead of components? This is, for example, what's done in examples/example-collaborative, or, in a simpler form, in this part of the custom components guide.

Since I want to apply change diffs within Yjs, it’s simpler to synchronize the component state directly rather than sending commands. Handling change diffs with Yjs is essential because Yjs relies on them to function as a CRDT, one of its core features. This allows users to stay synchronized without a centralized server, ensuring a consistent final state.

While command serialization is possible, keeping the final state consistent would require tracking the order of command applications. If an earlier, unapplied command is received, we would need to revert the state to its previous stage before reapplying subsequent commands. This makes the process unnecessarily complex.

Therefore, instead of working with commands themselves, we need an interface that extracts the change diffs applied to the component as a result of executing a command.

satoren avatar Feb 08 '25 01:02 satoren

https://y-phoenix.gigalixirapp.com/js-draw I have added a feature to display other users’ cursors. It would be great if objects being drawn by other users were also updated in real time. Is there a way to retrieve them?

satoren avatar Feb 10 '25 11:02 satoren

Therefore, instead of working with commands themselves, we need an interface that extracts the change diffs applied to the component as a result of executing a command.

I've pushed an (~~unreleased~~ released in 1.29.0) commit that may help with this: https://github.com/personalizedrefrigerator/js-draw/commit/be429feb16d5cbdb20ced18cfb65a2297bc3400e. It adds ComponentAdded and ComponentRemoved events to the editor.image object, with the ID of the component that was added or removed.

It would be great if objects being drawn by other users were also updated in real time. Is there a way to retrieve them?

At present, this might be possible by replacing the default Pen tool with a subclass, but it might be a bit complicated. The Pen subclass would:

  1. override previewStroke
  2. In previewStroke, call super.previewStroke.
  3. Build a preview of the in-progress stroke using this.builder.preview. Render to a custom SVGRenderer (or some other renderer type).
    • .build might also work, but in some stroke builders, it changes the current state.
  4. Send the preview to other clients.