Context: multi-user app (node.js) - 1 painter, n clients
Canvas size: 650x400 px (= 260,000 px)
For the canvas to be updated frequently (I'm thinking about 10 times a second), I need to keep the data size as small as possible, especially when thinking about upload rates.
The toDataURL()
method returning a base64 string is fine but it contains masses of data I don't even need (23 bit per pixel). Its length is 8,088 (without the preceding MIME information), and assuming the JavaScript strings have 8-bit encoding that would be 8.1 kilobytes of data, 10 times per second.
My next try was using JS objects for the different context actions like moveTo(x, y)
or lineTo(x, y)
, sending them to the server and have the clients receive the data in delta updates (via timestamps). However, this turned out to be even less efficient than the base64 string.
{
"timestamp": 0,
"what": {
"name": LINE_TO,
"args": {"x": x, "y": y}
}
}
It doesn't work fluently nor precisely because there are nearly 300 lineTo
commands already when you swipe your brush shortly. Sometimes there's a part of the movement missing (making a line straight instead of rounded), sometimes the events aren't even recognized by the script client-side because it seems to be "overwhelmed" by the mass of events triggered already.
So I have to end up using the base64 string with its 8.1 KB. I don't want to worry about this much - but even if done asynchronously with delta updates, there will be major lags on a real server, let alone the occasional bandwidth overrun.
The only colors I am using are #000 and #FFF, so I was thinking about a 1-bit data structure with delta updates only. This would basically suffice and I wouldn't mind any "color" precision losses (it is black after all).
With most of the canvas being white, you could think of additional Huffman run-length encoding to reduce size even further, too. Like a canvas with a size of 50x2 px and a single black pixel at (26, 2) would return the following string: 75W1B74W
(50 + 25 white pixels, then 1 black pixel, then 24 more white pixels)
It would even help if the canvas consisted of a 1-bit string like this:
00000000000000000000000000000000000000000000000000
00000000000000000000000001000000000000000000000000
That would help a lot already.
My first question is: How to write an algorithm to get this data efficiently?
The second is: How could I pass the pure binary canvas data to the clients (via node server)? How do I even send a 1-bit data structure to the server? Would I have to convert my bits to a hexadecimal (or more) number and re-parse?
Would it be possible to use this as a data structure?
Thanks in advance,
Harti