KineticJS : snap functionality using DragBoundFunc is not working for all shapes
Asked Answered
W

0

7

I implemented a function that detects collision between two shapes, and another function that limits the dragBound to the borders when collision is detected, in order to implement the snap functionality, and then add to Kinetic.Group. So practically I'm limiting the drop target to the borders of an existing rectangle.

Here's a jsfiddle for a clear view of my problem: http://jsfiddle.net/4Y87X/6/

This logic worked for the big rectangles, when width = height. But when I drag the little grey rectangle - which represents a window in my project - the collision is detected on the right and on top of the big rectangle only, the left and bottom are not detected! Is this due to some math equations in the DragBoundWindow method?

If anyone could locate the error, please?

CODE :

var stage = new Kinetic.Stage({
    container: "container",
    width: 900,
    height: 600
});
var leftLayer = new Kinetic.Layer({
    x:0,
    y:0,
    id: 'leftLayer',
    width:250,
    height:600
});
var leftBackground = new Kinetic.Rect({
    width: 250,
    height: 600,
    stroke: "red"
    });
leftLayer.add(leftBackground);
stage.add(leftLayer);

var rightLayer = new Kinetic.Layer({
    x: 280,
    y:0,
    id: 'rightLayer',
    width:600,
    height:600
});
var rightBackground = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 600,
    height: 600,
    stroke: "green"
    });
rightLayer.add(rightBackground);
stage.add(rightLayer);

//draw a room
var room = new Kinetic.Rect({
    width: 100,
    height: 100,
    fill: 'cornsilk',
    stroke: 'black',
    strokeWidth: 3,
    dragOnTop: false
});

var window = new Kinetic.Rect({
    x: 30,
    y: 250,
    width: 40,
    height: 4,
    name: 'window',
    id: "window_ID",
    fill: '#ccc',
    stroke: 'black',
    strokeWidth: 1
});

var rooms = [];
var id = 0

var group = new Kinetic.Group({
    x: 10,
    y: 100,
    width: 100,
    height: 100,
    id: id++
});
group.add(room);
leftLayer.add(group);
leftLayer.add(window);
stage.draw();

group.on('mousedown touchstart', function(e){
    if (e.which != 3) {
    var cloneOfItem= group.clone({added: false, id: id++});
    cloneOfItem.setDraggable(true);
    cloneOfItem.off('mousedown touchstart');
    leftLayer.add(cloneOfItem);

    cloneOfItem.dragBoundFunc(dragBoundCarre);

    cloneOfItem.on('dragmove', function(){
        this.moveToTop();
    });
    cloneOfItem.on('dragend', function(){
        var userPos = stage.getPointerPosition();
        if (userPos.x>280 && userPos.y>0 && !this.getAttr('added'))
        {
            this.setAttr('added', true);
            this.x(this.x() - 280);
            this.moveTo(rightLayer);
            rooms.push(this);
        }
        else if (userPos.x<280)
        {
            this.destroy();
            rightLayer.draw();
            rooms.splice(this,1);
        }
        stage.draw();
    });
     cloneOfItem.fire('mousedown');
     cloneOfItem.fire('touchstart');
    }
});

window.on('mousedown touchstart', function(e){
    if (e.which != 3) {
    var cw = window.clone({draggable:true});
    leftLayer.add(cw);
    cw.off('mousedown touchstart');

        cw.dragBoundFunc(dragBoundWindow);
    cw.on('dragstart', function(){
        this.startX=this.x();
        this.startY=this.y();
        this.lastPos=this.position();
        this.getParent().moveToTop();
    });
    cw.on('dragmove', function(){
        var pos=this.position();
        this.lastPos = pos;
        rightLayer.draw();
    });
    cw.on('dragend', function(e){
        var userPos = stage.getPointerPosition();
        if (userPos.x > 280 && userPos.y > 0)
        {
            var pos = cw.getAbsolutePosition();
            var x = pos.x;
            var y = pos.y;
            var hit = -1;
            for (var i = 0; i < rooms.length; i++) 
            {
                var c = rooms[i];
                var cpos = c.getAbsolutePosition();
                var cx = cpos.x + room.x();
                var cy = cpos.y + room.y();

                //detect collision
                if (x >= cx && x <= cx + c.width() && y >= cy && y <= cy + c.height()) 
                {
                    hit = i;
                    rooms[hit].off('dragend');
                    this.x(x - rooms[hit].x()-280);
                    this.y(y - rooms[hit].y());
                    this.moveTo(rooms[hit]);
                }
            }
            if (hit < 0)
            {
                this.x(x - 280);
                this.y(y);
                this.moveTo(rightLayer);            
                alert("Window is not in the rigth target. \n\nTry again.");
            }     
        }
        else 
        {
            this.remove();
        }
        rightLayer.draw(this);
        stage.draw();     
    });
    cw.fire('mousedown');
    cw.fire('touchstart');
    cw.fire('dragstart');
    }
    rightLayer.draw();
});

stage.add(rightLayer);
stage.add(leftLayer);
stage.draw();

function dragBoundCarre(pos, event) {
    var collided = doObjectsCollide(pos, this);
    if (collided.length > 1) {
        pos.x = this.getAbsolutePosition().x;
        pos.y = this.getAbsolutePosition().y;
    }
    else if (collided.length === 1) {
        collided = collided[0];
        var colAbsX = collided.getAbsolutePosition().x;
        var colAbsY = collided.getAbsolutePosition().y;
        var tempPos = Object.create(pos);

        tempPos.x -= colAbsX;
        tempPos.y -= colAbsY;

        if (Math.abs(tempPos.x) > Math.abs(tempPos.y) && tempPos.x < 0 && Math.abs(tempPos.x) < collided.width()) {
            pos.x = colAbsX - this.width();
        } else if (Math.abs(tempPos.x) > Math.abs(tempPos.y) && tempPos.x > 0 && Math.abs(tempPos.x) < collided.width()) {
            pos.x = colAbsX + collided.width();
        } else if (Math.abs(tempPos.x) < Math.abs(tempPos.y) && tempPos.y < 0 && Math.abs(tempPos.y) < collided.height()) {
            pos.y = colAbsY - this.height();
        } else if (Math.abs(tempPos.x) < Math.abs(tempPos.y) && tempPos.y > 0 && Math.abs(tempPos.y) < collided.height()) {
            pos.y = colAbsY + collided.height();
        }

    }
    return {
        x: pos.x,
        y: pos.y
    };
}

function dragBoundWindow(pos, event, group) {
    var collided = doObjectsCollide(pos, this);
    if (collided.length > 1) {
        pos.x = this.getAbsolutePosition().x;
        pos.y = this.getAbsolutePosition().y;
    }
    else if (collided.length === 1) {
        collided = collided[0];
        var colAbsX = collided.getAbsolutePosition().x;
        var colAbsY = collided.getAbsolutePosition().y;
        var tempPos = Object.create(pos);

        tempPos.x -= colAbsX;
        tempPos.y -= colAbsY;

        if (Math.abs(tempPos.x) > Math.abs(tempPos.y) && tempPos.x < 0 && Math.abs(tempPos.x) < collided.width()) {

            pos.x = colAbsX - this.width() + 40;
            //switch width and height          
            this.setWidth(window.getHeight());
            this.setHeight(window.getWidth());
            console.log('collision: left');
        } else if (Math.abs(tempPos.x) > Math.abs(tempPos.y) && tempPos.x > 0 && Math.abs(tempPos.x) < collided.width()) {
            pos.x = colAbsX + collided.width();
            this.setWidth(window.getHeight());
            this.setHeight(window.getWidth());
            console.log('collision: right');
        } else if (Math.abs(tempPos.x) < Math.abs(tempPos.y) && tempPos.y < 0 && Math.abs(tempPos.y) < collided.height()) {
            pos.y = colAbsY - this.height();
            this.setWidth(window.getWidth());
            this.setHeight(window.getHeight());            
            console.log('collision: top');
        } else if (Math.abs(tempPos.x) < Math.abs(tempPos.y) && tempPos.y > 0 && Math.abs(tempPos.y) < collided.height()) {
            pos.y = colAbsY + collided.height();
            this.setWidth(window.getWidth());
            this.setHeight(window.getHeight());
            console.log('collision: bottom');
        }
    }
    return {
        x: pos.x,
        y: pos.y
    };
    group.add(this);
}

function doObjectsCollide(pos, a) {
    var col = [];
    for (var i = 0; i < rooms.length; i++) {
        var b = rooms[i];
        if (a.id() != b.id()) {
            if (!((pos.y + a.getHeight()) < (b.getAbsolutePosition().y) || (pos.y > (b.getAbsolutePosition().y + b.getHeight())) || ((pos.x + a.getWidth()) < b.getAbsolutePosition().x) || (pos.x > (b.getAbsolutePosition().x + b.getWidth())))) 
            {
                col.push(b);
            }
        }
    }
    return col;
}
Wahkuna answered 29/4, 2014 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.