# connect a series of circles by line based on clicks

Hi

In this script below I have a series of circles with labels . I need to make them connectable by lines based on (x,y) coordinates of clicked

on  previous and current circle node . Now I can get the (X,y) coordinates of clicked circle .  I need to save the information from each

click so that it is available for  line drawing script both  . Here is the script : https://jsfiddle.net/sarmadm/4tr0ejnc/
###### Who is Participating?

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

PluritechnicianCommented:
Test page : https://jsfiddle.net/4tr0ejnc/1/

``````       if(dist <=30)
{
saveLabel=circles[i].label;
circX=circles[i].x;
circY=circles[i].y;
if(previous_clicked_circle) {
context.beginPath();
context.moveTo(previous_clicked_circle[0], previous_clicked_circle[1]);
context.lineTo(circX, circY);
context.stroke();
}
previous_clicked_circle = [circX, circY];
break; // break the loop
}
``````

``````<div id="wrap">
<p id="msg" class="blue">Please click on the page within the blue lines</p>
<canvas id="myCanvas" onclick="clickIt(event)" width="600" height="600">
</canvas>
</div>
``````

``````var previous_clicked_circle = null;
var circles = [];
circles[circles.length]=Circle({ x: 369, y: 116, label: "A" });
circles[circles.length]=Circle({ x: 231, y: 278, label: "1" });
circles[circles.length]=Circle({ x:133, y: 396, label: "D" });
circles[circles.length]=Circle({ x: 234, y: 511, label: "C" });
circles[circles.length]=Circle({ x: 351, y: 232, label: "B" });
circles[circles.length]=Circle({ x:348, y: 388, label: "4" });
circles[circles.length]=Circle({ x:164, y: 199, label: "5" });
circles[circles.length]=Circle({ x:522, y: 425, label: "3" });
circles[circles.length]=Circle({ x:229, y: 120, label: "E" });
circles[circles.length]=Circle({ x:493, y: 237, label: "2" });
//
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//
circles.forEach(function(circle) { circle.draw(); });
// --------------------
function Circle(I)
I.draw = function() {
context.beginPath();
context.arc(I.x, I.y, I.radius, 0, 2 * Math.PI, false);
context.fillStyle = 'white';
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#003300';
context.stroke();
context.font = '15pt Calibri';
context.fillStyle = 'black';
context.textAlign = 'center';
context.fillText(I.label, I.x, I.y);
};
return I;
}
// ----------
var xPos, yPos, circX, circY, saveLabel; // global
function clickIt(evt)
{ var i, xDiff, yDiff, dist, result, cX, cY;
xPos=null; yPos=null; circX=null; circY=null; saveLabel=""
evt= evt || event;
xPos=evt.offsetX || evt.pageX;
yPos=evt.offsetY || evt.pageY;
// check posn against centres

for( i=0;i<circles.length;i++)
{ cX=circles[i].x; cY=circles[i].y;
xDiff=Math.abs(cX-xPos);
yDiff=Math.abs(cY-yPos);
dist=Math.sqrt(Math.pow(xDiff,2)+Math.pow(yDiff,2));
// info on clicked circle
if(dist <=30)
{
saveLabel=circles[i].label;
circX=circles[i].x;
circY=circles[i].y;
if(previous_clicked_circle) {
context.beginPath();
context.moveTo(previous_clicked_circle[0], previous_clicked_circle[1]);
context.lineTo(circX, circY);
context.stroke();
}
previous_clicked_circle = [circX, circY];
break; // break the loop
}
}
}

function drawArrow(from, to)
{
var radians = Math.PI / 180;
var angle = Math.atan(Math.abs(from.y - to.y) / Math.abs(from.x - to.x));
var rise = from.radius * Math.sin(angle);
var run = to.radius * Math.cos(angle);
context.beginPath();
if (from.x < to.x) {
from.x += run;
to.x -= run;
} else {
from.x -= run;
to.x += run;
}
if (from.y < to.y) {
from.y += rise;
to.y -= rise;
} else {
from.y -= rise;
to.y += rise;
}
context.moveTo(from.x, from.y);
context.lineTo(to.x, to.y);
context.stroke();
context.lineTo(to.x - headlen * Math.cos(angle - Math.PI / 6), to.y - headlen * Math.sin(angle - Math.PI / 6));
context.moveTo(to.x, to.y);
context.lineTo(to.x - headlen * Math.cos(angle + Math.PI / 6), to.y - headlen * Math.sin(angle + Math.PI / 6));
context.stroke();
}

// ---------
``````

``````body {
font-family: arial, helvetica, sans-serif;
font-weight: normal;
font-size: 13px;
color: #000;
text-align: left;
margin: 3px 0px;
}

#wrap {
margin: 20px;
}

#myCanvas {
border: 1px solid blue;
}

.blue {
font-size: 18px;
font-weight: bold;
color: #00F;
}
``````

Experts Exchange Solution brought to you by

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Commented:
I worked on this yesterday but ran out of time to finish. I modified your code, however, your arrow heads still need some work as the sometimes draw incorrectly. I'm not sure if leakim already answered but I already did the work so posting anyway. Hope this helps.

I include it as a standalone html file below.

Regards
Pierre

``````<!DOCTYPE html>
<html>
<style>
body {
font-family: arial, helvetica, sans-serif;
font-weight: normal;
font-size: 13px;
color: #000;
text-align: left;
margin: 3px 0px;
}

#wrap {
margin: 20px;
}

#myCanvas {
border: 1px solid blue;
}

.blue {
font-size: 18px;
font-weight: bold;
color: #00F;
}

</style>
<body>
<div id="wrap">
<p id="msg" class="blue">Please click on the page within the blue lines</p>
<canvas id="myCanvas" onclick="clickIt(event)" width="600" height="600">
</canvas>
</div>

<script>
var circles = [];
circles[circles.length]=Circle({ x: 369, y: 116, label: "A" });
circles[circles.length]=Circle({ x: 231, y: 278, label: "1" });
circles[circles.length]=Circle({ x:133, y: 396, label: "D" });
circles[circles.length]=Circle({ x: 234, y: 511, label: "C" });
circles[circles.length]=Circle({ x: 351, y: 232, label: "B" });
circles[circles.length]=Circle({ x:348, y: 388, label: "4" });
circles[circles.length]=Circle({ x:164, y: 199, label: "5" });
circles[circles.length]=Circle({ x:522, y: 425, label: "3" });
circles[circles.length]=Circle({ x:229, y: 120, label: "E" });
circles[circles.length]=Circle({ x:493, y: 237, label: "2" });
//
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//
circles.forEach(function(circle) { circle.draw(); });
// --------------------
function Circle(I)
I.draw = function() {
context.beginPath();
context.arc(I.x, I.y, I.radius, 0, 2 * Math.PI, false);
context.fillStyle = 'white';
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#003300';
context.stroke();
context.font = '15pt Calibri';
context.fillStyle = 'black';
context.textAlign = 'center';
context.fillText(I.label, I.x, I.y);
};
return I;
}
// ----------

// global
var last_circle_index=-1;

function index_of_circle(x,y)
{
//return index of circle at x and y coords
var i, dist, xDiff, yDiff;
for( i=0;i<circles.length;i++)
{
xDiff=Math.abs(circles[i].x-x);
yDiff=Math.abs(circles[i].y-y);
dist=Math.sqrt(Math.pow(xDiff,2)+Math.pow(yDiff,2));
// info on clicked circle
if(dist <=30) return i;

}
}

function clickIt(evt)
{ var i=-1, cx, cy;
//xPos=null; yPos=null; circX=null; circY=null; saveLabel=""
evt= evt || event;
cx=evt.offsetX || evt.pageX;
cy=evt.offsetY || evt.pageY;
// check posn against centres
i = index_of_circle(cx, cy);
if (i!=-1 && last_circle_index!=-1)
{
//two circles clicked consecutively
drawArrow(circles[last_circle_index], circles[i]);
}
last_circle_index = i;
}

function drawArrow(from, to)
{
//from and to are references to the circle objects. use local vars in order to not change circle object values
var fx= from.x, fy=from.y, tx=to.x, ty=to.y;

var radians = Math.PI / 180;
var angle = Math.atan(Math.abs(from.y - to.y) / Math.abs(from.x - to.x));
var rise = from.radius * Math.sin(angle);
var run = to.radius * Math.cos(angle);
context.beginPath();
if (fx < tx) {
fx += run;
tx -= run;
} else {
fx -= run;
tx += run;
}
if (fy < ty) {
fy += rise;
ty -= rise;
} else {
fy -= rise;
ty += rise;
}
context.moveTo(fx, fy);
context.lineTo(tx, ty);
context.stroke();

//this needs work: arrow heads sometimes drawn incorrectly...
context.lineTo(tx - headlen * Math.cos(angle - Math.PI / 6), ty - headlen * Math.sin(angle - Math.PI / 6));
context.moveTo(tx, ty);
context.lineTo(tx - headlen * Math.cos(angle + Math.PI / 6), ty - headlen * Math.sin(angle + Math.PI / 6));
context.stroke();
}

// ---------

</script>
</body>
</html>
``````
Author Commented: