I've got a question which i can't seem to figure out the right way. For some context. I'm trying to make a sort of connect the dots game. People can click on a circle and link the circle to the next one. Connecting the dots is working fine, but i wanted to add a function that when clicked on the first dot, users get a perfect straight line from the clicked dot to the mouse input. This way the users get some feedback on which dot they clicked, and how they can link to each other.
Here is a codePen that shows what i want to achieve. The only thing different is that the dots in this "pen" are animated, and i want them to stand still.
I tried a lots of things so far, and found multiple StackOverflow articles about this subject. So far i got connecting the dots working. Also the user draws a line when a dot is selected. The big issue however is that every movement of the user is resulting in drawing a line on the canvas. This line which is only used as feedback which dot is selected and how the user can draw his cursor to the next dot, is filling the screen with thousands of instances in no-time. I only want to show them one single line at a time, leading to their mouse cursor as the endpoint. Just like the codePen i did mention earlier on.
Here is my JS code so far.
var dotColor = "#FF0000";
var strokeColor = "#FF0000";
var mouse = {
x: undefined,
y: undefined
};
var obj;
var data = {
canvas: null,
ctx: null,
clickedDot: null,
dots: [{
x: 180,
y: 50
}, {
x: 20,
y: 50
}]
};
window.addEventListener('mousemove', function(e) {
mouse.x = e.x;
mouse.y = e.y;
renderActiveLink();
});
function circleCollision(c1, c2) {
var a = c1.r + c2.r,
x = c1.x - c2.x,
y = c1.y - c2.y;
if (a > Math.sqrt((x * x) + (y * y))) return true;
else return false;
}
function prepCanvas() {
var res = window.devicePixelRatio || 1,
scale = 1 / res;
data.canvas = document.getElementById('dots');
data.ctx = data.canvas.getContext('2d');
data.canvas.width = 500;
data.canvas.height = 300;
data.ctx.scale(res, res);
data.canvas.addEventListener('mousedown', function(e) {
checkForDot(e);
});
data.canvas.addEventListener('mouseup', function(e) {
checkForDot(e);
});
}
function drawDots() {
var i = 0;
for (; i < data.dots.length; i++) {
var d = data.dots[i];
data.ctx.beginPath();
data.ctx.arc(d.x, d.y, 5, 0, 2 * Math.PI);
data.ctx.fillStyle = dotColor;
data.ctx.fill();
data.ctx.closePath();
}
}
function drawLine(toDot) {
data.ctx.beginPath();
data.ctx.moveTo(data.clickedDot.x, data.clickedDot.y);
data.ctx.lineTo(toDot.x, toDot.y);
data.ctx.lineWidth = 5;
data.ctx.strokeStyle = strokeColor;
data.ctx.stroke();
data.ctx.closePath();
}
function checkForDot(e) {
var i = 0,
col = null;
for (; i < data.dots.length; i++) {
var d = data.dots[i],
c1 = {
x: d.x,
y: d.y,
r: 50
},
c2 = {
x: e.pageX,
y: e.pageY,
r: 50
};
if (circleCollision(c1, c2)) {
col = d;
}
}
if (col !== null) {
if (data.clickedDot !== null) drawLine(col);
data.clickedDot = col;
obj = col;
} else data.clickedDot = null;
}
function renderActiveLink() {
data.ctx.beginPath();
data.ctx.lineWidth = 5;
data.ctx.shadowBlur = 0;
data.ctx.moveTo(obj.x, obj.y);
data.ctx.lineTo(mouse.x, mouse.y);
data.ctx.strokeStyle = '#000000';
data.ctx.stroke();
}
prepCanvas();
drawDots();
*{
margin:0;
padding: 0;
}
#dots {
border: 1px solid black;
}
<canvas id="dots"></canvas>
Also to be seen in this JSFiddle.
Hope someone here can help me out. If any more information is needed, i will be glad to answer your questions :D.
This code just to help you to use canvas
.
I added a start status in the data.
var data = {
start: false, // initial value is false
canvas: null,
ctx: null,
clickedDot: null,
dots: [{
x: 180,
y: 50
}, {
x: 20,
y: 50
}]
};
And i changed start state in the mousedown
and mouseup
listeners.
data.canvas.addEventListener('mousedown', function(e) {
data.start = true
checkForDot(e);
});
data.canvas.addEventListener('mouseup', function(e) {
data.start = false
checkForDot(e);
});
so the renderActiveLink
method, Only works when the start position is true
.
and Clears everything before drawing each line.
function renderActiveLink() {
if(!data.start) return;
data.ctx.clearRect(0, 0, data.canvas.width, data.canvas.height);
drawDots();
...
Final code:
var dotColor = "#FF0000";
var strokeColor = "#FF0000";
var mouse = {
x: undefined,
y: undefined
};
var obj;
var data = {
start: false,
canvas: null,
ctx: null,
clickedDot: null,
dots: [{
x: 180,
y: 50
}, {
x: 20,
y: 50
}]
};
window.addEventListener('mousemove', function(e) {
mouse.x = e.x;
mouse.y = e.y;
renderActiveLink();
});
function circleCollision(c1, c2) {
var a = c1.r + c2.r,
x = c1.x - c2.x,
y = c1.y - c2.y;
if (a > Math.sqrt((x * x) + (y * y))) return true;
else return false;
}
function prepCanvas() {
var res = window.devicePixelRatio || 1,
scale = 1 / res;
data.canvas = document.getElementById('dots');
data.ctx = data.canvas.getContext('2d');
data.canvas.width = 500;
data.canvas.height = 300;
data.ctx.scale(res, res);
data.canvas.addEventListener('mousedown', function(e) {
data.start = true
checkForDot(e);
});
data.canvas.addEventListener('mouseup', function(e) {
data.start = false
checkForDot(e);
});
}
function drawDots() {
var i = 0;
for (; i < data.dots.length; i++) {
var d = data.dots[i];
data.ctx.beginPath();
data.ctx.arc(d.x, d.y, 5, 0, 2 * Math.PI);
data.ctx.fillStyle = dotColor;
data.ctx.fill();
data.ctx.closePath();
}
}
function drawLine(toDot) {
data.ctx.beginPath();
data.ctx.moveTo(data.clickedDot.x, data.clickedDot.y);
data.ctx.lineTo(toDot.x, toDot.y);
data.ctx.lineWidth = 5;
data.ctx.strokeStyle = strokeColor;
data.ctx.stroke();
data.ctx.closePath();
}
function checkForDot(e) {
var i = 0,
col = null;
for (; i < data.dots.length; i++) {
var d = data.dots[i],
c1 = {
x: d.x,
y: d.y,
r: 50
},
c2 = {
x: e.pageX,
y: e.pageY,
r: 50
};
if (circleCollision(c1, c2)) {
col = d;
}
}
if (col !== null) {
if (data.clickedDot !== null) drawLine(col);
data.clickedDot = col;
obj = col;
} else data.clickedDot = null;
}
function renderActiveLink() {
if(!data.start) return;
data.ctx.clearRect(0, 0, data.canvas.width, data.canvas.height);
drawDots();
data.ctx.beginPath();
data.ctx.lineWidth = 5;
data.ctx.shadowBlur = 0;
data.ctx.moveTo(obj.x, obj.y);
data.ctx.lineTo(mouse.x, mouse.y);
data.ctx.strokeStyle = '#000000';
data.ctx.stroke();
}
prepCanvas();
drawDots();
*{
margin:0;
padding: 0;
}
#dots {
border: 1px solid black;
}
<canvas id="dots"></canvas>