1

I'm currently thinking about using fabric.js for an on-line handwriting recognition system. For such a system, I would need to send the drawn lines as a list of lines, where each line is a list of points.

So if the user has drawn an "x" on the canvas, I would like to get something like this:

[
  // the first line was the one going from left bottom to right top:
  [{'x':228, 'y':92}, 
    {'x':229, 'y':90}, 
    {'x':230, 'y':88}, 
    {'x':232, 'y':86}, 
    {'x':235, 'y':84}, 
    {'x':238, 'y':81}, 
    {'x':243, 'y':76}, 
    {'x':248, 'y':70}, 
    {'x':256, 'y':64}, 
    {'x':265, 'y':58}, 
    {'x':275, 'y':52}, 
    {'x':285, 'y':46}, 
    {'x':295, 'y':39}, 
    {'x':307, 'y':33}, 
    {'x':317, 'y':28}, 
    {'x':328, 'y':23}, 
    {'x':334, 'y':19}, 
    {'x':341, 'y':14}, 
    {'x':348, 'y':9}, 
    {'x':352, 'y':7}, 
    {'x':353, 'y':6}, 
    {'x':354, 'y':5}, 
    {'x':354, 'y':4}
   ],
   // the second line was the one going from left top to right bottom
   [
    {'x':259, 'y':20}, 
    {'x':260, 'y':21}, 
    {'x':261, 'y':22}, 
    {'x':262, 'y':23}, 
    {'x':264, 'y':26}, 
    {'x':266, 'y':28}, 
    {'x':268, 'y':31}, 
    {'x':271, 'y':34}, 
    {'x':274, 'y':38}, 
    {'x':279, 'y':44}, 
    {'x':285, 'y':51}, 
    {'x':291, 'y':59}, 
    {'x':297, 'y':67}, 
    {'x':303, 'y':74}, 
    {'x':309, 'y':80}, 
    {'x':315, 'y':88}, 
    {'x':321, 'y':96}, 
    {'x':328, 'y':103}, 
    {'x':334, 'y':107}, 
    {'x':340, 'y':112}, 
    {'x':345, 'y':116}, 
    {'x':349, 'y':118}, 
    {'x':350, 'y':119}, 
    {'x':350, 'y':120}
    ]
]
  • The first element in the first list should be the point drawn first.
  • For 0 <= i < j: Every element of list j was drawn later than any element of list i.

Question: How do I get such a list of lines, where each list is represented as a list of points? Can I also get some "speed indicator", e.g. a time attribute for each point?

My try

<!DOCTYPE html>
<html>
<head>
    <title>Handwriting recognition example</title>
    <script src="all.min.js"></script>
</head>
<body>
    <canvas id="c1" width="800" height="450" style="border:1px solid black;"></canvas>
    <script>
        var canvas = new fabric.Canvas('c1');
        canvas.isDrawingMode = true;
    </script>
</body>
</html>

It seems as if all free-drawn lines are stored in canvas._objects as a list of fabric.Path. Is that correct?

The relevant attributes seem to be:

  • top: This seems to be an offset of the path.
  • width: What is this good for?
  • path: Is this the list of points for a single line? This seems to be a list of lists. What do the elements mean? Every sub-list seems to begin with either M, Q or L where M seems to be the first element, L the last and Q everything in between (M=moveto, Q=quadratic Bézier curve, L=lineto, source). The first and the last contain only 2 numeric values, all points in between have 4 numeric values. I guess that 2 numeric values are x/y coordinates. But what do the other two coordinates mean?

Note

If you show me a possibility to use freehand drawing with the export of points / lines that does not use fabric.js, that's fine, too. But touch screens have to work with that solution!

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958

1 Answers1

1

This is a different approach, but might help to achieve your goal:

var canvas = new fabric.Canvas('c',{backgroundColor: 'rgb(200,200,200)'});
canvas.isDrawingMode = true;
var rect = new fabric.Rect();

canvas.add(rect);

canvas.on('mouse:down', function(options) {
  startRecording();
});

var lines = [];


function startRecording(){
    var line = [];
    canvas.on('mouse:move', recordMoment);
    canvas.on("mouse:up", stopRecording);

    function recordMoment(event){
        line.push({x: event.e.x, y: event.e.y});    
        console.log(event.e.x + " " + event.e.y);    
    }
    function stopRecording(){
        lines.push(line);
        canvas.off('mouse:move', recordMoment);
        canvas.off("mouse:up", stopRecording);
    }
}

http://jsfiddle.net/B5Ub9/4/

Instead of analyzing the curves present on the screen, this code is recording touch positions while lines are drawn on canvas by the user.

EDIT added isDrawingMode to show the lines on canvas.

kihu
  • 842
  • 5
  • 13
  • Hmm ... ok. But I also would like to be able to restore it. When I do it this way, I don't see a possiblity to restore the same drawing, because Fabric.js seems to use bezier curves. – Martin Thoma Apr 01 '14 at 15:46
  • Also, this event-based solution would enable you to gather time (speed) data. – kihu Apr 02 '14 at 08:27
  • One (important) information that gets lost with your current way is when the user started a new line. So when you only have this list of coordinates, a user who draws a "U" and a user who draws a "| |" might look exactly the same. – Martin Thoma Apr 02 '14 at 18:49
  • When you use this mirroring fiddle, you can see that information is lost: http://jsfiddle.net/MartinThoma/C2737/ – Martin Thoma Apr 02 '14 at 19:12
  • Just reset lastPoint every time user starts drawing a line http://jsfiddle.net/qcP5W/ – kihu Apr 03 '14 at 08:26
  • But look at the result. If no information was lost, then the left side should be exactly equal to the right side (except that the right side is red). But it isn't: http://i.imgur.com/IXzIV3p.png – Martin Thoma Apr 03 '14 at 08:40
  • Information is obviously lost. You can't gather all the points of a line, cause it's an infinite amount of points. That's why you need to reconstruct it using methods I've mentioned above. I've fixed that to work in ff http://jsfiddle.net/qcP5W/5/ – kihu Apr 03 '14 at 09:24
  • The line that gets drawn by Fabric.js is defined by finite points. So in principle there has to be a possibility to get the exact same result. – Martin Thoma Apr 03 '14 at 09:39