0

I want to draw a path on my canvas on the fly. I know how to do this is using following HTML5 canvas code:

$('#drawing-canvas').mousedown(function(e){
    startx = e.pageX;
    starty = e.pageY;
    cxt.beginPath();
    cxt.moveTo(startx,starty);
 });

$('#drawing-canvas').mousemove(function(e){
    cxt.lineTo(e.pageX,e.pageY);
    cxt.strokeStyle='red'; 
    cxt.lineWidth = 1;     
    cxt.stroke();
 });

My question is how do I accomplish the same thing using KineticJS.

Update:

I think something like this may work.

  $('#container').mousemove(function(e){
  var pen = new Kinetic.Shape({
    drawFunc: function(canvas) {
      var context = canvas.getContext();
      if(moving == false){ // grab the start xy coords from mousedown event
      context.beginPath();
      context.moveTo(startx,starty);
      moving = true;
      }
      context.lineTo(e.pageX,e.pageY);
      context.strokeStyle='#ff00ff'; 
      context.lineWidth = 1;     
      context.stroke();
   }
     penlayer.add(pen);
     stage.add(penlayer); 
  });
 });

However, handling the beginPath() and moveTo(..) is proving to be problematic. I need to set these on a mousedown event. Any ideas?

Update:

The effect I am trying to get can be seen by selecting the pen option at http://www.redshiftsolutions.com/demos/whiteboard/whiteboard.html. This is a simple collaborative whiteboard that uses canvas and jQuery. I want to transition this to KineticJS because of the added drag and drop functionality.

user1884367
  • 425
  • 2
  • 7
  • 15
  • yes, I came across this too. It draws a straight line between the begin and end points of the mouse movement. I tried modifying the code to build a series of line segments with the new segment start point equal to the last segment endpoint, but it only draws the last segment. – user1884367 Jan 07 '13 at 22:51
  • Thank you for you comments. I agree my code has issues partly because of my unfamiliarity Kinetic. I will try to put up some revised code on Fiddle in due course. In the meantime I have updated my question to add some additional clarity. – user1884367 Jan 09 '13 at 01:25
  • The link to "redshiftsolutions.com" is dead. Can you update it? – Martin Thoma Apr 03 '14 at 16:13

3 Answers3

2

Here: http://jsfiddle.net/akhiyadav1/k4qB8/22/ take a look at how this person did it.

Basically you do create a new Kinetic.Line() and push points to it each time the mouse moves.

Try this code:

<!DOCTYPE HTML>
<html>
  <head>
      <style>
        body {
            margin: 0px;
            padding: 0px;
        }
        canvas {
            border: 1px solid #9C9898;
        }
    </style>
    <script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.1.js"></script>
    <script>
        window.onload = function() {
            layer = new Kinetic.Layer();
            stage = new Kinetic.Stage({
                container: "container",
                width: 320,
                height: 320
            });

            background = new Kinetic.Rect({
                x: 0, 
                y: 0, 
                width: stage.getWidth(),
                height: stage.getHeight(),
                fill: "white"
            });

            line = new Kinetic.Line({
                points: [0, 0, 50, 50],
                stroke: "red"
            });

            layer.add(background);
            layer.add(line);
            stage.add(layer);

            moving = false;

            stage.on("mousedown", function(){
                if (moving){
                    moving = false;layer.draw();
                } else {
                    var mousePos = stage.getMousePosition();
                    //start point and end point are the same
                    line.getPoints()[0].x = mousePos.x;
                    line.getPoints()[0].y = mousePos.y;
                    line.getPoints()[1].x = mousePos.x;
                    line.getPoints()[1].y = mousePos.y;

                    moving = true;    
                    layer.drawScene();            
                }

            });

            stage.on("mousemove", function(){
                if (moving) {
                    var mousePos = stage.getMousePosition();
                    var x = mousePos.x;
                    var y = mousePos.y;
                    line.getPoints()[1].x = mousePos.x;
                    line.getPoints()[1].y = mousePos.y;
                    moving = true;
                    layer.drawScene();
                }
            });

            stage.on("mouseup", function(){
                moving = false; 
            });

        };
    </script>
</head>
<body>
    <div id="container" ></div>
</body>

SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98
0

Put your code in a jsfiddle and I'll play around with it. But looking at it, it seems your code is a bit wrong.

Each time the mouse moves you are redefining a local variable pen and re-adding the same pen layer. And its structured a bit off. Try:

$('#container').mousemove(function(e){
   var pen = new Kinetic.Shape({
      drawFunc: function(canvas) {
          var context = canvas.getContext();
          if(moving == false){ 
              context.beginPath();
              context.moveTo(startx,starty);
              moving = true;
          }
          context.lineTo(e.pageX,e.pageY);
          context.strokeStyle='#ff00ff'; 
          context.lineWidth = 1;     
          context.stroke();
      } 
  });

  penlayer.add(pen);
  stage.add(penlayer);
});

You would also be better off with something that uses the other mouse events for better control, assuming you are looking to create straight lines.

 $('#container').mousedown(function(e){
       //draw temporary shape
 }
 $('#container').mousemove(function(e){
       //redraw shape
 }
 $('#container').mouseup(function(e){
       //add shape to layer
 }

Also, why don't you use Kinetic.Line() and something like:

 var startLine; // make this global because this can be redefined 
 $('#container').mousedown(function(e){
    startLine = new Kinetic.Line({
         points: [stage.getUserPosition().x, stage.getUserPosition().y],
         stroke: 'red',
         strokeWidth: 15,
         lineCap: 'round',
         lineJoin: 'round'
    });
 }
 $('#container').mouseUp(function(e){
    var endLine = new Kinetic.Line({
         points: [startLine.getX(), startLine.getY(), stage.getUserPosition().x, stage.getUserPosition().y],
         stroke: 'red',
         strokeWidth: 15,
         lineCap: 'round',
         lineJoin: 'round'
    });
    layer.add(endLine);
 }

This is a very rough solution, and you'd have to resolve the scope of startLine and endLine.

SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98
0

here how I implemented it. The key is to use spline shape of kineticJS and push points in it during mousemove and mouseup. ev._x, ev._y are the x, and y points calculated in the light of this post Tracking mouse position in canvas when no surrounding element exists

Please let me know if it helps

tools.pencil = function () {
var tool = this;
this.started = false;
var drawObject;

this.mousedown = function (ev) {
    drawObject = new DrawObject();
    drawObject.Tool = DrawTool.Pencil;
    tool.started = true;
    drawObject.currentState = DrawState.Started;
    drawObject.StartX = ev._x;
    drawObject.StartY = ev._y;
    tool.DrawIt(drawObject);

};

this.mousemove = function (ev) {
    if (tool.started) {
        drawObject.currentState = DrawState.Inprogress;
        drawObject.CurrentX = ev._x;
        drawObject.CurrentY = ev._y;
        tool.DrawIt(drawObject);

    }
};

this.mouseup = function (ev) {
    if (tool.started) {
        tool.started = false;
        drawObject.currentState = DrawState.Completed;
        drawObject.CurrentX = ev._x;
        drawObject.CurrentY = ev._y;
        tool.DrawIt(drawObject);
    }
};
this.mouseout = function (ev) {
    if (tool.started) {
    }
    tool.started = false;

};

this.DrawIt = function (drawObject) {

        switch (drawObject.currentState) {
            case DrawState.Started:
                var x= drawObject.StartX, 
                    y = drawObject.StartY;
                var pencil = new Kinetic.Spline({
                    points: [{
                        x: x,
                        y: y
                    }],
                    stroke: 'red',
                    strokeWidth: 2,
                    lineCap: 'round',
                    tension: 1,
                    name: shapes.length
                });

                drawObject.Shape = pencil;
                layer.add(pencil);
                layer.draw();


                break;
            case DrawState.Inprogress:
            case DrawState.Completed:
                var x = drawObject.CurrentX,
                    y = drawObject.CurrentY;

                var pencil = drawObject.Shape;
                pencil.attrs.points.push({ x: x, y: y });
                pencil.setPoints(pencil.attrs.points);
                layer.draw();
                if (drawObject.currentState == DrawState.Completed) {
                    // dosomething
                }

                break;
        }

}

Where draw object is simple empty function in javascript

function DrawObject()
{
}

and drawstate is all the available state of pencil tool

var DrawState =
{
 Started: 0,
 Inprogress: 1,
 Completed: 2
}

and "layer" is simple KineticJS layer already added in KineticJS stage

Community
  • 1
  • 1