在Canvas上绘制可调整大小的矩形

时间:2015-09-12 10:33:28

标签: javascript html canvas

我试图在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

1 个答案:

答案 0 :(得分:1)

mouseMove中的逻辑有点含糊不清,因此我尝试将其改为更清晰的陈述:

  1. 如果不拖动,请继续检查鼠标是否与任何矩形碰撞,如果碰到任何矩形,请获取rectHandle。

  2. 如果您在rectHandle存在时丢失了,请将drag设置为true

  3. 因此,我们知道如果drag为真,您不必再次检查碰撞,只需使用selected,这是您从collides获取的选定矩形索引开始计算新的矩形。

  4. 一些更改按预期工作,更改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();
    }