Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raphael JS Implementing a "Pencil" tool efficiently

I am working on a project that requires end users to be able draw in the browser much like svg-edit and send SVG data to the server for processing.

I've started playing with the Raphael framework and it seems promising.

Currently I am trying to implement a pencil or freeline type tool. Basically I am just drawing a new path based on percentage of mouse movement in the drawing area. However, in the end this is going to create massive amount of paths to deal with.

Is it possible to shorten an SVG path by converting mouse movement to use Curve and Line paths instead of line segments?

Below is draft code I whipped up to do the job ...

    // Drawing area size const
   var SVG_WIDTH = 620;
   var SVG_HEIGHT = 420;

   // Compute movement required for new line
   var xMove = Math.round(SVG_WIDTH * .01);
   var yMove = Math.round(SVG_HEIGHT * .01);

   // Min must be 1
   var X_MOVE = xMove ? xMove : 1;
   var Y_MOVE = yMove ? yMove : 1;

   // Coords
   var start, end, coords = null;
   var paperOffset = null;
   var mouseDown = false;

   // Get drawing area coords
   function toDrawCoords(coords) {
    return {
     x: coords.clientX - paperOffset.left,
     y: coords.clientY - paperOffset.top
    };
   }

   $(document).ready(function() {
    // Get area offset
    paperOffset = $("#paper").offset();
    paperOffset.left = Math.round(paperOffset.left);
    paperOffset.top = Math.round(paperOffset.top);
    // Init area
    var paper = Raphael("paper", 620, 420);
    // Create draw area
    var drawArea = paper.rect(0, 0, 619, 419, 10)
    drawArea.attr({fill: "#666"});

    // EVENTS
    drawArea.mousedown(function (event) {
     mouseDown = true;
     start = toDrawCoords(event);
     $("#startCoords").text("Start coords: " + $.dump(start));
    });
    drawArea.mouseup(function (event) {
     mouseDown = false;
     end = toDrawCoords(event);
     $("#endCoords").text("End coords: " + $.dump(end));
     buildJSON(paper);
    });
    drawArea.mousemove(function (event) {
     coords = toDrawCoords(event);
     $("#paperCoords").text("Paper coords: " + $.dump(coords));
     // if down and we've at least moved min percentage requirments
     if (mouseDown) {
      var xMovement = Math.abs(start.x - coords.x);
      var yMovement = Math.abs(start.y - coords.y);
      if (xMovement > X_MOVE || yMovement > Y_MOVE) {
       paper.path("M{0} {1}L{2} {3}", start.x, start.y, coords.x, coords.y);
       start = coords; 
      }
     }
    });


   }); 
like image 309
Almost Famous Avatar asked Jan 05 '11 03:01

Almost Famous


2 Answers

Have a look at the Douglas-Peucker algorithm to simplify your line.

I don't know of any javascript implementation (though googling directed me to forums for google maps developers) but here's a tcl implementation that is easy enough to understand: http://wiki.tcl.tk/27610

And here's a wikipedia article explaining the algorithm (along with pseudocode): http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

like image 87
slebetman Avatar answered Sep 28 '22 09:09

slebetman


Here is a drawing tool which works with the iPhone or the mouse http://irunmywebsite.com/raphael/drawtool2.php However also look at Daves "game utility" @ http://irunmywebsite.com/raphael/raphaelsource.php which generates path data as you draw.

like image 43
Chasbeen Avatar answered Sep 28 '22 11:09

Chasbeen