我怎样才能在 HTML Canvas 中制作一条绑定到鼠标输入的直线
How can i make a single straight line in HTML Canvas which is bound to the input of the mouse
我有一个问题,我似乎无法找出正确的方法。对于某些上下文。我正在尝试制作一种点点滴滴的游戏。人们可以点击一个圈子,然后 link 圈子转到下一个圈子。连接点工作正常,但我想添加一个功能,当点击第一个点时,用户从点击的点到鼠标输入得到一条完美的直线。通过这种方式,用户可以获得关于他们点击了哪个点的一些反馈,以及他们如何 link 彼此。
这是一个 codePen 显示我想要实现的目标。唯一不同的是这支“笔”中的点是动画的,我希望它们静止不动。
到目前为止,我尝试了很多东西,并找到了多篇关于这个主题的 Whosebug 文章。到目前为止,我已经把这些点连接起来了。用户还可以在选择一个点时绘制一条线。然而,最大的问题是用户的每一个动作都会导致在 canvas 上画一条线。这行仅用作反馈选择了哪个点以及用户如何将光标绘制到下一个点,立即用数千个实例填满屏幕。我只想一次向他们显示一行,将他们的鼠标光标作为端点。就像我之前提到的codePen。
到目前为止,这是我的 JS 代码。
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>
也可以在这个JSFiddle中看到。
希望这里有人能帮助我。如果需要更多信息,我很乐意回答您的问题:D.
此代码只是为了帮助您使用canvas
。
我在数据中添加了开始状态。
var data = {
start: false, // initial value is false
canvas: null,
ctx: null,
clickedDot: null,
dots: [{
x: 180,
y: 50
}, {
x: 20,
y: 50
}]
};
并且我在 mousedown
和 mouseup
听众中更改了开始状态。
data.canvas.addEventListener('mousedown', function(e) {
data.start = true
checkForDot(e);
});
data.canvas.addEventListener('mouseup', function(e) {
data.start = false
checkForDot(e);
});
所以renderActiveLink
方法,只在起始位置为true
时有效。
并在绘制每条线之前清除所有内容。
function renderActiveLink() {
if(!data.start) return;
data.ctx.clearRect(0, 0, data.canvas.width, data.canvas.height);
drawDots();
...
最终代码:
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>
我有一个问题,我似乎无法找出正确的方法。对于某些上下文。我正在尝试制作一种点点滴滴的游戏。人们可以点击一个圈子,然后 link 圈子转到下一个圈子。连接点工作正常,但我想添加一个功能,当点击第一个点时,用户从点击的点到鼠标输入得到一条完美的直线。通过这种方式,用户可以获得关于他们点击了哪个点的一些反馈,以及他们如何 link 彼此。
这是一个 codePen 显示我想要实现的目标。唯一不同的是这支“笔”中的点是动画的,我希望它们静止不动。
到目前为止,我尝试了很多东西,并找到了多篇关于这个主题的 Whosebug 文章。到目前为止,我已经把这些点连接起来了。用户还可以在选择一个点时绘制一条线。然而,最大的问题是用户的每一个动作都会导致在 canvas 上画一条线。这行仅用作反馈选择了哪个点以及用户如何将光标绘制到下一个点,立即用数千个实例填满屏幕。我只想一次向他们显示一行,将他们的鼠标光标作为端点。就像我之前提到的codePen。
到目前为止,这是我的 JS 代码。
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>
也可以在这个JSFiddle中看到。
希望这里有人能帮助我。如果需要更多信息,我很乐意回答您的问题:D.
此代码只是为了帮助您使用canvas
。
我在数据中添加了开始状态。
var data = {
start: false, // initial value is false
canvas: null,
ctx: null,
clickedDot: null,
dots: [{
x: 180,
y: 50
}, {
x: 20,
y: 50
}]
};
并且我在 mousedown
和 mouseup
听众中更改了开始状态。
data.canvas.addEventListener('mousedown', function(e) {
data.start = true
checkForDot(e);
});
data.canvas.addEventListener('mouseup', function(e) {
data.start = false
checkForDot(e);
});
所以renderActiveLink
方法,只在起始位置为true
时有效。
并在绘制每条线之前清除所有内容。
function renderActiveLink() {
if(!data.start) return;
data.ctx.clearRect(0, 0, data.canvas.width, data.canvas.height);
drawDots();
...
最终代码:
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>