Link to home
Start Free TrialLog in
Avatar of Ivan Golubar
Ivan Golubar

asked on

Using clicking on canvas to get coordinates to draw lines and anchor circles

Code below is from  http://fabricjs.com/stickman and it is using fabrics.js library. (try to drag circle by pressing on mouse and moving)

Now coordinates for lines and circles are set by code. My goal is to set coordinates by clicking on canvas.

First click will be start and to determinate the end of polyline I need to use double click. I did try some options until now but i hope this one will be okay, as it has option to move lines by anchor circle. once the polyline has already been created for editing purposes.

Am sure i will have to use on click event and on double click event.  So when i will click on fist point i will get circle. Next click will give me the second  circle and the line between them and so on until double click. For now i have only one restriction and that is not to generate another circle, if i am clicking on existing  circle.

What would be the logic to get coordinates by clicking on canvas and to draw while clicking ?





 var line1,line2,line3,line4 ; 
function createObject(){  

fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

function makeCircle(left, top, line1, line2, line3, line4) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#666'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;
    c.line3 = line3;
    c.line4 = line4;

    return c;
  }
 
 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
      selectable: false
    });
  }

  var line1 = makeLine([ 250, 125, 300, 175 ]),
      line2 = makeLine([ 300, 175, 350, 225 ]),
      line3 = makeLine([ 350, 225, 400, 275]),
      line4 = makeLine([ 400, 275, 450, 325]);

  canvas.add(line1, line2, line3, line4);
  
   canvas.add(
    makeCircle(line1.get('x1'), line1.get('y1'), null,line1),
    makeCircle(line1.get('x2'), line1.get('y2'), line1,line2),
    makeCircle(line2.get('x2'), line2.get('y2'), line2,line3),
    makeCircle(line3.get('x2'), line3.get('y2'), line3,line4),
    makeCircle(line4.get('x2'), line4.get('y2'), line4)
  );

    }               
document.getElementById("clickMe").onclick = createObject;


var moveHandler = function (evt) {
    var obj = evt.target;

    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line3 && obj.line3.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line4 && obj.line4.set({ 'x1': obj.left, 'y1': obj.top });
    canvas.renderAll();
/}
canvas.on('object:moving', moveHandler);

Open in new window

Avatar of Ivan Golubar
Ivan Golubar

ASKER

I want as first to draw line, then i will add also circles.
So, next code should not do anything at first click and then on second click draw line from first click point to second one.

To get there I have as first resolve next:
why var posX1=0;
is then undefined  inside canvas on mouse down function?
(pleas check attached picture)


var line1=[ ];

 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
     //selectable: false
    });
 }
 
var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
canvas.on('mouse:down', function(e) {
  posX1 = posX2;
  posY1 = posY2;
  var pointer = canvas.getPointer(e.e);
  var posX2 = pointer.x;
  var posY2 = pointer.y;
  
  if (lineCount!=0){
  line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
  canvas.add(line1[lineCount]);
  } 
     lineCount=lineCount+1;
 }

Open in new window

linecor.png
Avatar of Leonidas Dosas
Could you post all the code (html+js) in a attached file?
I can't find link to online fabric library.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">


<script src="https://can't find /fabric.min.js" ></script
 
<style>



</style>

<script>
var canvas = new fabric.Canvas('c');
 
  
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';



var line1=[ ];

 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
     //selectable: false
    });
 }


var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
canvas.on('mouse:down', function(e) {
  posX1 = posX2;
  posY1 = posY2;
  var pointer = canvas.getPointer(e.e);
  var posX2 = pointer.x;
  var posY2 = pointer.y;
  
  if (lineCount!=0){
  line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
  canvas5.add(line1[lineCount]);
  }
  
 });
</script>
</head>
<body>
       <canvas  id="c" width="1060" height="550"  > 

 
</div>
</body></html>

Open in new window

Check this script:
<script>
var canvas = new fabric.Canvas('c');
 
  
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';



var line1=[ ];

 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
     //selectable: false
    });
 }


var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;

 canvas.on('mouse:down', function(e) {
 if(lineCount===0){
  var pointer = canvas.getPointer(e.e);
   posX2 = pointer.x;
   posY2 = pointer.y;
  lineCount++
  return;
  }else{
   var pointer = canvas.getPointer(e.e);
   posX1=pointer.x;
   posY1 = pointer.y;
   line1 = makeLine([posX1, posY1, posX2, posY2 ]);
   canvas.add(line1);
   lineCount=0;
  } 

  
  
 });
 
</script>

Open in new window

I have got the mistake. Sorry.

var posX2 = pointer.x;
  var posY2 = pointer.y;


I get lines now.
Is it works now?
Yes. I will now go on with drawing of circles.
I had to get back to my previous code, because your code is doing, separate lines, but i need polyline which continues until i make a double click (check the begging of this question). I did add also circles between lines to have the anchor point for move handler.
Check the second attached code. When circles are pressed and moved lines should follow them. Under point 1 is original code from first post of this question. under point 2 is my try, but unsuccessful and under 3  the same as 2. With next  error:
Uncaught TypeError: Cannot read property '0' of undefined for line 19 of second code snippet.

To recapitulate:
 Now i am missing
1 double click to end the polyline.
2 move handler
3 check the attached picture: I don't want to ses line in circle  


var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
canvas.on('mouse:down', function(e) {
 posX1 = posX2;
  posY1 = posY2;
  var pointer = canvas.getPointer(e.e);
   posX2 = pointer.x;
   posY2 = pointer.y;
  
     var RP = document.getElementById("RadioPol").checked;
  
  if (RP) {
      
       if (lineCount!=0){
       line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
       canvas.add(line1[lineCount]);
       } 
 
      if (lineCount==0){canvas.add(makeCircle( posX2, posY2, null));}
      if (lineCount>0){canvas.add( makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount-1],line1[lineCount]));}
      }
      
     lineCount=lineCount+1;
     

Open in new window


 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
  /*
     1.
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line3 && obj.line3.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line4 && obj.line4.set({ 'x1': obj.left, 'y1': obj.top });
    canvas.renderAll();

    2.
       for (var i = 0, len = lineCount; i < len; i++) {
           obj.line1[i] && obj.line1[i].set({ 'x2': obj.left, 'y2': obj.top });
       }
         3.  */
    obj.line1[0] && obj.line1[0].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[1] && obj.line1[1].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[2] && obj.line1[2].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[3] && obj.line1[4].set({ 'x2': obj.left, 'y2': obj.top });
    

Open in new window

7.png
Could you post all the code please because they are missing elements like "RadioPol"?
Consider point 1 (from my last post) double click to end the polyline done.
No need to use double click. I will just  check, if i am clicking on any object to end the polyline.

But i still need help with:
2 move handler
3 check the attached picture(previous post): I don't want to see line in circle.  


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">

 <script src=".................../fabric.min.js"></script>
 
 
<style>



</style>

<script>

var line1=[];

 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
    selectable: false
    });
 }
  function makeCircle(left, top, line1, line2) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 2,
      radius: 6,
      fill: '#fff',
      stroke: '#666'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;

    return c;
  }
  
 
var clickonobject ;
var objectIndex;
var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
function drawPoly(){
  
     var RP = document.getElementById("RadioPol").checked;
  
  if (RP) {
      
       if (lineCount!=0){
       line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
       canvas.add(line1[lineCount]);
       } 
 
      if (lineCount==0){canvas.add(makeCircle( posX2, posY2, null));}
      if (lineCount>0){canvas.add( makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount-1],line1[lineCount]));}
      }
      
     lineCount=lineCount+1;    
}
canvas.on('mouse:down', function(e) {
    var obj2 = e.target;
    if (obj2!= null){console.log(obj2.type);}
   
  if (obj2==null){
       //if (obj2.type== Circle){lineCount=0;}
      // else{
         posX1 = posX2;
         posY1 = posY2;
         var pointer = canvas.getPointer(e.e);
         posX2 = pointer.x;
         posY2 = pointer.y;
         drawPoly();//}
      }else{lineCount=0;}

  });


var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);

  /*
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line3 && obj.line3.set({ 'x1': obj.left, 'y1': obj.top });
    obj.line4 && obj.line4.set({ 'x1': obj.left, 'y1': obj.top });
    canvas.renderAll();

    
       for (var i = 0, len = lineCount; i < len; i++) {
           obj.line1[i] && obj.line1[i].set({ 'x2': obj.left, 'y2': obj.top });
       }
           
    obj.line1[0] && obj.line1[0].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[1] && obj.line1[1].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[2] && obj.line1[2].set({ 'x2': obj.left, 'y2': obj.top });
    obj.line1[3] && obj.line1[4].set({ 'x2': obj.left, 'y2': obj.top });
    */
</script>
</head>
<body>
       <canvas  id="c" width="1060" height="550"  > 

 
</div>
</body></html>

Open in new window

Next code is moving only line before the circle and not the other one.


var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
 

    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
}

Open in new window


The problem is in next line:
if (lineCount>0){canvas.add( makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount],line1[lineCount+1]));}

When i am making circles as anchor point i don't have  yet the next line (i have the line before circle and not yet the line after circle)

So i must each time i make new line find the previouse circle and add to him  line which was just been made. How to do that?
With next code also the problem number 2 is resolved.
Now when I press on circle i may drag both lines which are attached to specific circle as circle is moving.

     
if (lineCount==0){
          circle1[lineCount]=makeCircle( posX2, posY2, null,null);
          canvas.add(circle1[lineCount]); 
      }
      if (lineCount>0){
         circle1[lineCount]= makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount],null);
         canvas.add(circle1[lineCount]); 
         circle1[lineCount-1].line2 =line1[lineCount];
      } 

Open in new window


Now about problem from point 3.  ( small part of line is in the circle ( Check attached picture))
I am not sure  if i could leave it as it is, as it gives me the direction of line creation. So consider this question closed.


How to assign points?
Untitled8.png
Ivan I used your previous code ID 42519818 but unfortunately I haven't any output in my browser.Could you check again and repost your code?
ASKER CERTIFIED SOLUTION
Avatar of Ivan Golubar
Ivan Golubar

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
In the last post is my complete working code.