我试图在canvas元素上绘制可调整大小的矩形。我检查鼠标相对于屏幕上矩形的位置,然后更新鼠标所在的三角形的宽度/高度。到目前为止,除了减少元素宽度/高度外,我还是成功的。这是因为鼠标位置在矩形坐标范围内。
我如何处理扩张?这是代码
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
rect = [],
handlesSize = 4,
currentHandle = false,
drag = false,
selected = false;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function point(x, y) {
return {
x: x,
y: y
};
}
function collides(rects, x, y) {
var isCollision = false;
for (var i = 0, len = rects.length; i < len; i++) {
var left = rects[i].x, right = rects[i].x+rects[i].w;
var top = rects[i].y, bottom = rects[i].y+rects[i].h;
if (right >= x
&& left <= x
&& bottom >= y
&& top <= y) {
isCollision = i;
}
}
return isCollision;
}
function dist(p1, p2) {
return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
function getHandle(e,mouse) {
var returned = false;
selected = collides(rect, e.offsetX, e.offsetY);
if(selected || selected === 0)
{
if (dist(mouse, point(rect[selected].x, rect[selected].y)) <= handlesSize) returned = 'topleft';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y)) <= handlesSize) returned = 'topright';
if (dist(mouse, point(rect[selected].x, rect[selected].y + rect[selected].h)) <= handlesSize) returned = 'bottomleft';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y + rect[selected].h)) <= handlesSize) returned = 'bottomright';
if (dist(mouse, point(rect[selected].x + rect[selected].w / 2, rect[selected].y)) <= handlesSize) returned = 'top';
if (dist(mouse, point(rect[selected].x, rect[selected].y + rect[selected].h / 2)) <= handlesSize) returned = 'left';
if (dist(mouse, point(rect[selected].x + rect[selected].w / 2, rect[selected].y + rect.h)) <= handlesSize) returned = 'bottom';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y + rect[selected].h / 2)) <= handlesSize) returned = 'right';
}
return returned;
}
function mouseDown(e) {
if (currentHandle)
{
draw();
drag = true;
}
else
{
var mousePos = point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
rect.push({x: mousePos.x, y: mousePos.y, w: 80, h: 20});
draw();
drag = true;
selected = collides(rect, e.offsetX, e.offsetY);
}
}
function mouseUp() {
drag = false;
currentHandle = false;
draw();
}
function mouseMove(e) {
var previousHandle = currentHandle;
if (!drag) currentHandle = getHandle(e,point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop));
selected = collides(rect, e.offsetX, e.offsetY);
var select = rect[selected];
if (currentHandle && drag && selected) {
var mousePos = point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
var select = rect[selected];
switch (currentHandle) {
case 'topleft':
rect[selected].w += select.x - mousePos.x;
rect[selected].h += select.y - mousePos.y;
rect[selected].x = mousePos.x;
rect[selected].y = mousePos.y;
break;
case 'topright':
rect[selected].w = mousePos.x - rect[selected].x;
rect[selected].h += rect[selected].y - mousePos.y;
rect[selected].y = mousePos.y;
break;
case 'bottomleft':
rect[selected].w += rect[selected].x - mousePos.x;
rect[selected].x = mousePos.x;
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'bottomright':
rect[selected].w = mousePos.x - rect[selected].x;
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'top':
rect[selected].h += rect[selected].y - mousePos.y;
rect[selected].y = mousePos.y;
break;
case 'left':
rect[selected].w += rect[selected].x - mousePos.x;
rect[selected].x = mousePos.x;
break;
case 'bottom':
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'right':
rect[selected].w = mousePos.x - rect[selected].x;
break;
}
}
if (drag || currentHandle != previousHandle) draw();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'black';
$.each(rect,function(i,item)
{
ctx.fillRect(item.x, item.y, item.w, item.h);
});
if (currentHandle) {
var posHandle = [];
posHandle = point(0, 0);
switch (currentHandle) {
case 'topleft':
posHandle.x = rect[selected].x;
posHandle.y = rect[selected].y;
break;
case 'topright':
posHandle.x = rect[selected].x + rect[selected].w;
posHandle.y = rect[selected].y;
break;
case 'bottomleft':
posHandle.x = rect[selected].x;
posHandle.y = rect[selected].y + rect[selected].h;
break;
case 'bottomright':
posHandle.x = rect[selected].x + rect[selected].w;
posHandle.y = rect[selected].y + rect[selected].h;
break;
case 'top':
posHandle.x = rect[selected].x + rect[selected].w / 2;
posHandle.y = rect[selected].y;
break;
case 'left':
posHandle.x = rect[selected].x;
posHandle.y = rect[selected].y + rect[selected].h / 2;
break;
case 'bottom':
posHandle.x = rect[selected].x + rect[selected].w / 2;
posHandle.y = rect[selected].y + rect[selected].h;
break;
case 'right':
posHandle.x = rect[selected].x + rect[selected].w;
posHandle.y = rect[selected].y + rect[selected].h / 2;
break;
}
ctx.globalCompositeOperation = 'xor';
ctx.beginPath();
ctx.arc(posHandle.x, posHandle.y, handlesSize, 0, 2 * Math.PI);
ctx.fill();
ctx.globalCompositeOperation = 'source-over';
}
}
init();
你可以在这里看到一个活泼的小提琴js fiddle
答案 0 :(得分:1)
mouseMove
中的逻辑有点含糊不清,因此我尝试将其改为更清晰的陈述:
如果不拖动,请继续检查鼠标是否与任何矩形碰撞,如果碰到任何矩形,请获取rectHandle。
如果您在rectHandle存在时丢失了,请将drag
设置为true
。
因此,我们知道如果drag
为真,您不必再次检查碰撞,只需使用selected
,这是您从collides
获取的选定矩形索引开始计算新的矩形。
一些更改按预期工作,更改jsfiddle到演示:
碰撞
function collides(rects, x, y) {
// Set search index to -1 rather than false if nothing collides.
// This will make the return value stick to Number, so we don't need to
// care check if it is 0 and not false in your origin code.
var isCollision = -1;
for (var i = 0, len = rects.length; i < len; i++) {
var left = rects[i].x, right = rects[i].x+rects[i].w;
var top = rects[i].y, bottom = rects[i].y+rects[i].h;
if (right >= x
&& left <= x
&& bottom >= y
&& top <= y) {
isCollision = i;
}
}
return isCollision;
}
gethandle
function getHandle(e,mouse) {
var returned = false;
// Remove this, do it outside.
// selected = collides(rect, e.offsetX, e.offsetY);
if(selected || selected === 0)
{
// You can use the else if logic here, so when a handle is found,
// it don't keep check if other handles are valid.
// But note that when rect is small, if else way would return topleft
// while current code would return right.
if (dist(mouse, point(rect[selected].x, rect[selected].y)) <= handlesSize) returned = 'topleft';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y)) <= handlesSize) returned = 'topright';
if (dist(mouse, point(rect[selected].x, rect[selected].y + rect[selected].h)) <= handlesSize) returned = 'bottomleft';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y + rect[selected].h)) <= handlesSize) returned = 'bottomright';
if (dist(mouse, point(rect[selected].x + rect[selected].w / 2, rect[selected].y)) <= handlesSize) returned = 'top';
if (dist(mouse, point(rect[selected].x, rect[selected].y + rect[selected].h / 2)) <= handlesSize) returned = 'left';
if (dist(mouse, point(rect[selected].x + rect[selected].w / 2, rect[selected].y + rect.h)) <= handlesSize) returned = 'bottom';
if (dist(mouse, point(rect[selected].x + rect[selected].w, rect[selected].y + rect[selected].h / 2)) <= handlesSize) returned = 'right';
}
return returned;
}
鼠标移动
function mouseMove(e) {
var previousHandle = currentHandle;
// If not dragging, check collision
if (!drag) {
selected = collides(rect, e.offsetX, e.offsetY);
// If collides with something, get handle
// You can move this part into collides
if (selected >= 0) {
currentHandle = getHandle(e,point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop));
}
} else {
// If drag is true, selected and currentHandle is guranteed to have value in your logic.
var mousePos = point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
var select = rect[selected];
switch (currentHandle) {
case 'topleft':
rect[selected].w += select.x - mousePos.x;
rect[selected].h += select.y - mousePos.y;
rect[selected].x = mousePos.x;
rect[selected].y = mousePos.y;
break;
case 'topright':
rect[selected].w = mousePos.x - rect[selected].x;
rect[selected].h += rect[selected].y - mousePos.y;
rect[selected].y = mousePos.y;
break;
case 'bottomleft':
rect[selected].w += rect[selected].x - mousePos.x;
rect[selected].x = mousePos.x;
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'bottomright':
rect[selected].w = mousePos.x - rect[selected].x;
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'top':
rect[selected].h += rect[selected].y - mousePos.y;
rect[selected].y = mousePos.y;
break;
case 'left':
rect[selected].w += rect[selected].x - mousePos.x;
rect[selected].x = mousePos.x;
break;
case 'bottom':
rect[selected].h = mousePos.y - rect[selected].y;
break;
case 'right':
rect[selected].w = mousePos.x - rect[selected].x;
break;
}
}
// If dragging or currentHandle changed, draw it
if (drag || currentHandle != previousHandle) draw();
}