The toolkit which you are most experienced in.
You can implement this in any toolkit, as long as you correctly design the application; for instance:
- You will not need "multi-threaded" painting, for the seemingly parallel painting effect users will see: instead
- Use events. Send events, like "draw curve" or "draw straight line", to notify all participants of updates to the drawing.
- Use frame synchronization. Each participant keeps a stack of events, which are ordered on time of occurrence, which gets updated by user-generated events (like the "draw this" and "draw that"). On a regular interval, a client will send it's stack of events to other participants.
- Implement your own "garbage collection": if an event is not modifying any pixels because other events overlap it, it can be discarded (removed from the stack) to improve performance on synchronizing frames and drawing.
- Implement event collapsing. For instance 4 events saying: "draw line from x to y", "draw line from y to z", etc. can be collapsed in a path-like-shape.
The client will only have to listen for events and add them to it's local frame, draw the shared frame (by each time painting, redrawing all events on an empty canvas), send the events over the network to other clients and listen for events and keyframes from other clients.
The drawing is single-threaded: it will collect all stacks (local, and per participant), orders it on time of occurrence and paint it in that order. This is supported by all mentioned frameworks.
Quite a #complex #dynamic #system, though.