I implemented a function that detects a collision between two shapes and another function that limits dragBound to borders when a collision is detected, to implement the snap functionality, and then add it to Kinetic.Group . Therefore, in practice, I limit the purpose of the drop to the borders of the existing rectangle.
Here's jsfiddle for a clear view of my problem: http://jsfiddle.net/4Y87X/6/
This logic worked for large rectangles when width = height. But when I drag a small gray rectangle, which is a window in my project, a collision is detected on the right and on top of a large rectangle , not found on the left and bottom! Is this due to some mathematical equations in the DragBoundWindow?
If anyone can find a mistake please?
THE 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; }