下面是如何通过拖放在
<canvas>
上绘制“选择矩形”,请参阅如何在 HTML 画布上通过拖放绘制选择矩形?。
是否有一种简单的方法可以检测悬停在几个像素距离处的选择矩形,并允许通过拖放来移动选择矩形?
var c1 = document.getElementById("c1"), c2 = document.getElementById("c2");
var ctx1 = c1.getContext("2d"), ctx2 = c2.getContext("2d");
ctx2.setLineDash([5, 5]);
var origin = null;
window.onload = () => { ctx1.drawImage(document.getElementById("img"), 0, 0); }
c2.onmousedown = e => { origin = {x: e.offsetX, y: e.offsetY}; };
window.onmouseup = e => { origin = null; };
c2.onmousemove = e => {
if (!!origin) {
ctx2.strokeStyle = "#ff0000";
ctx2.clearRect(0, 0, c2.width, c2.height);
ctx2.beginPath();
ctx2.rect(origin.x, origin.y, e.offsetX - origin.x, e.offsetY - origin.y);
ctx2.stroke();
}
};
#img { display: none; }
#canvas-container { position: relative; }
canvas { position: absolute; left: 0; top: 0; }
#c1 { z-index: 0; }
#c2 { z-index: 1; }
<img id="img" src="https://i.imgur.com/okSIKkW.jpg">
<div id="canvas-container">
<canvas id="c1" height="200" width="200"></canvas>
<canvas id="c2" height="200" width="200"></canvas>
</div>
为了能够移动现有的选择,您必须保存其状态。现在,您的代码在绘制一次后就会“忘记”它。
您可以将您的选择保存在
mouseup
上的变量中,如下所示:
const dx = origin.x - mouse.x;
const dy = origin.y - mouse.y;
selection = {
left: Math.min(mouse.x, origin.x),
top: Math.min(mouse.y, origin.y),
width: Math.abs(dx),
height: Math.abs(dy)
}
您的选择是一个矩形。您可以像这样检查鼠标是否与矩形相交:
const intersects = (
mouse.x >= selection.left &&
mouse.x <= selection.left + selection.width &&
mouse.y >= selection.top &&
mouse.y <= selection.top + selection.height
);
如果您想在矩形周围添加一些填充,您可以将复选框更改为,例如,
mouse.x >= selection.left - PADDING
。
您现在必须支持两种类型的交互:
这是我的实现有点混乱的地方,但你可以自己重构它🙂
除了将选择保存到变量之外,我没有对选择代码进行太多更改。
移动选区时,您可以拖动鼠标拖动
dx
和 dy
,并将它们添加到选区的 原始 位置 (ox, oy
):
const dx = origin.x - mouse.x;
const dy = origin.y - mouse.y;
selection.left = ox - dx;
selection.top = oy - dy;
这是可运行片段中的所有内容:
var c1 = document.getElementById("c1"),
c2 = document.getElementById("c2");
var ctx1 = c1.getContext("2d"),
ctx2 = c2.getContext("2d");
ctx2.setLineDash([5, 5]);
var origin = null;
let selection = null;
let selectionHovered = false;
let interaction = null;
let ox = null;
let oy = null;
window.onload = () => { ctx1.drawImage(document.getElementById("img"), 0, 0); }
c2.onmousedown = e => {
origin = {x: e.offsetX, y: e.offsetY};
if (selectionHovered) {
interaction = "MOVE_SELECTION";
ox = selection.left;
oy = selection.top;
} else {
interaction = "MAKE_SELECTION";
}
};
window.onmouseup = e => {
interaction = null;
origin = null;
};
c2.onmousemove = e => {
const x = e.offsetX;
const y = e.offsetY;
if (!interaction) {
selectionHovered = (
selection &&
x >= selection.left &&
x <= selection.left + selection.width &&
y >= selection.top &&
y <= selection.top + selection.height
);
} else {
const dx = origin.x - x;
const dy = origin.y - y;
// Update
switch (interaction) {
case "MOVE_SELECTION":
selection.left = ox - dx;
selection.top = oy - dy;
break;
case "MAKE_SELECTION":
selection = {
left: Math.min(x, origin.x),
top: Math.min(y, origin.y),
width: Math.abs(dx),
height: Math.abs(dy)
}
break
default:
// Do nothing
}
// Set selectionHovered
if (selection) {
} else {
selectionHovered = false;
}
}
// Draw
if (selection) drawSelection(selection);
};
function drawSelection({ top, left, width, height }) {
// Draw rect
ctx2.strokeStyle = "#ff0000";
ctx2.clearRect(0, 0, c2.width, c2.height);
ctx2.beginPath();
ctx2.rect(left, top, width, height);
ctx2.stroke();
// Set mouse
c2.style.cursor = selectionHovered ? "move" : "default";
}
#img { display: none; }
body { margin: 0; }
#canvas-container { position: relative; }
canvas { position: absolute; left: 0; top: 0; }
#c1 { z-index: 0; }
#c2 { z-index: 1; }
<img id="img" src="https://i.imgur.com/okSIKkW.jpg">
<div id="canvas-container">
<canvas id="c1" height="200" width="200"></canvas>
<canvas id="c2" height="200" width="200"></canvas>
</div>