簡體   English   中英

在畫布上繪制可調整大小的矩形

[英]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為更清晰的語句:

  1. 如果不拖動,請繼續檢查鼠標是否與任何矩形發生碰撞,如果與任何矩形發生碰撞,請獲取rectHandle。

  2. 並且如果在rectHandle存在時drag鼠標向下drag ,請將drag設置為true

  3. 因此,我們知道如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM