A few months back I had created an application that recorded and played back drawings on HTML5 Canvas. For some time now I wanted to refactor the code in that application and create a reusable ‘component’ from it. Which is what I did this week.
Go ahead and try the demo first – Press ‘Record’ key below and then draw some strokes/lines in the box with the mouse (holding down left button). Once you are done, click Stop button. Click ‘Play’ button to play back the drawing you just drew. You can pause and resume too.
Interesting piece of code in this application is to record strokes. You would have observed that, when playing back the drawing, the component does not draw all strokes at once, but it plays them backs in the sequence you had drawn, maintaining the time line. To do this, I collect all the strokes that are drawn in a certain time interval (in this application, it is 100 millis) and create a linked list. Each collection (of strokes) in this linked list stores time elapsed from the start of the recording.
When playing back, I use time elapsed in the first collection to start drawing strokes. Each subsequent collection is drawn after the difference between time elapsed for that collection and the previous collection.
You can find all the code in this file. ‘RecordableDrawing’ is the object you would create by passing id of the canvas –
drawing = new RecordableDrawing("canvas1");
This object captures strokes and draws them. ‘Recording’ object handles time slotting each stroke and playing them back, as described above. ‘ActionsSet’ object contains collection of strokes and also time interval from the start of the recording.
If you want Mobile version of this component, created using JQueryMobile, then you can find the demo here. All objects/functions for drawing are defined in RecordableDrawing.js.
See the updated version of code and example (with features to set stroke color and size) in my blog post Record and Playback Drawing in HTML5 Canvas – Part II
34 Replies to “Record and Playback Drawing in HTML5 Canvas”
This coding is totally different and distinguishing your code from other “frame set” recording methodologies implementation. It only saves the points and time-lapse information, which means a lot smaller in size for the same effect of recording and playing-back. Even though, I cannot understand every piece of your coding, it seems a great idea for hand-writing “whiteboard” application.
Can you possibly provide a hint for saving the recording in a file and playing back at a later time?
In the application that I build using this code, I save and load recordings using JSON. Each recording contains chain of actions sets. Each action set contains array of actions. The approach I have taken is to create a copy of recording object with array of action sets (instead of linked list of actions sets), which contains array of actions. Then I simply call stringify method of JSON on the copy of recording object.
Loading of recording is also similar. I read text from a file and call JSON.parse. This gives me recording object. Then I create linked list of actions sets from array of action sets.
If I get time, I will update this example with save and load options, but that doesn’t seem possible very soon.
hi ram, i have been trying to play with your code to run with different line width and color, but it seems that the configuration on top of recordableDrawing isn’t taking effect. I was able to change background color, but linewidth and drawingcolor never got applied. Could you try it on your end and see if it works?
never i figured out why it happens. They weren’t in the self. global namespace. 🙂
Dear mr. Kulkarni, The replay is wonderful! Please allow me to ask your advice in a matter that concerns many painters. Our files are trapped in a famous painting app for iPad called ‘Brushes’. Brushes (open source) uses a desktop ‘Brushes viewer’ that enables to replay brushstrokes and export paintings at 6x their size without loss of resolution. This wonderful feature is indispensable for printing. However the viewer doesn’t work and paintings can’t be printed. The issue exists for at least four years. Some artists have years of work in the app. We have history.json files and they seem o.k. The image container also has a file ‘image.json’ but this seems to have a syntax error. I don’t know anything about errors or programming (I suppose few painters do). How should we go about this? Could this problem be fixed? Do you know if it would be possible to use these files with some other program that allows a resize of the brushstrokes? Thank you for showing your work and provide a way to make contact.
wicked awesome. thanks for the super cool code, Ram!
Any update on _saving_ and loading the drawingrecord?
Unfortunately, no.It is stil on my TODO list, but low in priority. However in an earlier comment on this post I have explained how this could be done.
For those who were asking for implementation of saving and loading recordings, see my blog post De/Serializing Recordings in Recordable HTML5 Canvas
Ram, it’s simply amazing work.,
Did you test it on Android Chrome. I did it is not work? Can you say why?
I did not test my blog post in Android Chrome. But when I did that after reading your comment, I see that mouse events are not captured by the Canvas but are propagated to Browser Window. That could be the reason why drawing does not work in Android browser.
However I have used the code in a standalone Android application and it had worked fine. Unfortunately presently I don’t have enough time to debug this issue in Android Chrome.
Could you package this in say a github or .zip file?
I am going to try to implement this canvas drawing over a video and utilize audio recording!
Take a look at the followup post on this. I have implemented selections of stroke color and size. There are only two JS files required – RecordableDrawing.js and drawingSerializer.js. Feel free to use them for your implementation.
Hi Ram, i mentioned about above code not work android chrome. But i noticed your mobile version and i used it. But it was good on chrome v34..v36 but now v39 bad. I read your answer. You said “I have used the code in a standalone Android application and it had worked fine. ” what do you mean stand alone android application. Can you explain. Thanks
I had created an HTML5 Android app using the Canvas described in this post. It worked fine with Android WebView. It was a couple of years back. Haven’t tried that app with the latest Android WebView.
hey there Ram – thanks for this blog post – truly helpful. I was trying to run your code provided here but i keep getting a blank result could you also provide link to your html code to jun your .js file. thanks
Can it be possible to add images on to the canvas and record that too.
Yes, it is possible. Inserting image in the Canvas should be easy. To record it, you will need to serialize this action. If an image is coming from a URL then you could serialize the URL, or you could convert the image to base64 and serialize it. Similarly deserializer would construct image either from a URL or base64 data.
hi ..dis is seriously awesome….but does it work with fabirc.js canvas ?
I haven’t worked with FabricJS. Drawing APIs could be different, I am not sure.
This is really awesome. I extend your library and add voice recording and image functionalities. Now I want to add image dragging and resize functionalities. please help me in this regard.
Hii can you share your code
Links to code files are already in the blog.
This is totally awesome. I would like to add another button (ex: Rectangle) that would in turn perform the same functions but draw a rectangle. Can you help point me in the right direction?
Add a (toggle) button to select rectangle mode. You may need to add a state variable for this in the RecordableDrawing class/function. You will also need to add an action class for Rectangle, similar to the Point class which is already there. When rectangle mode is selected, on mouse down event, create a Rectangle action. Mouse move event will not create Point actions, but will probable just draw an outline of the rectangle (erase previous outline with the background color and draw a new one with current co-ordinates). On mouseup event set the final co-ordinates of the rectangle, add the rectangle action to current recording (if one exists) and draw the rectangle (you will need to add a case statement for rectangle in RecordableDrawing.drawAction).
Superb i really enjoyed very much with this article here. Really its a amazing article i had ever read. I hope it will help a lot for all. Thank you so much for this amazing posts and please keep update like this excellent article.
Awesome Work Ram ,
how can i smooth drawing on canvas ? i tried QuadraticCurve but , it doesnt work , how can i draw like sketchtoy.com ?? it so importtant for me , pls help me , help us .
sorry very bad at coding how do i connect my canvas with this drawing = new RecordableDrawing(“canvas1”) what is supposed to be the “drawing” ?
Open http://ramkulkarni.com/temp/2012-10-03/ in the browser and view source code (right click on the page and select the option to view page source). You will see how RecordableDrawing is used. BTW drawing is a variable holding instance of RecordableDrawing.
Ram, I have a canvas stock chart which gets updated with new data points. How can I record the entire action going on in that canvas over time into a video which I can later save to aws and share a link. Any form of guidance would be helpful
Very nice tutorial. But I have noticed something.
1. When I’m playing back the recording after pausing, then the playback starts after few seconds, that is, the next element gets drawn after a while which was not the original case while drawing it.
2. Is it possible to save the recording to db, then play it again later? If yes, then which objects of the recording should be saved and how?
Regarding #2, please take a look at my post De/Serializing Recordings in Recordable HTML5 Canvas. You could save serialized data to DB and later retrieve and play it.
There are onPlayStart error is coming. Please help!