[英]Drawing resizable rectangles on 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();
你可以在這里看到一個現場小提琴
mouseMove
的邏輯有點模棱兩可,因此我嘗試將其mouseMove
為更清晰的語句:
如果不拖動,請繼續檢查鼠標是否與任何矩形發生碰撞,如果與任何矩形發生碰撞,請獲取rectHandle。
並且如果在rectHandle存在時drag
鼠標向下drag
,請將drag
設置為true
。
因此,我們知道如果drag
為true,則不必再次檢查碰撞,只需使用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();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.