var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var isDown=false;
var startX,startY,dragging;
ctx.translate(0.50,0.50);
ctx.textAlign='center';
ctx.textBaseline='middle';
var pts;
var p1={x:50,y:50,w:25,h:25,fill:''};
var p2={x:250,y:250,w:25,h:25,fill:''};
var ob={x:100,y:150,w:125,h:25,fill:''};
var obVertices=[
{x:ob.x,y:ob.y},
{x:ob.x+ob.w,y:ob.y},
{x:ob.x+ob.w,y:ob.y+ob.h},
{x:ob.x,y:ob.y+ob.h}
];
var s1,s2,s3,e1,e2,e3,o1,o2,o3,o4;
draw();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});
function draw(){
ctx.clearRect(0,0,cw,ch);
//
ctx.lineWidth=4;
ctx.globalAlpha=0.250;
ctx.strokeStyle='blue';
ctx.strokeRect(ob.x,ob.y,ob.w,ob.h);
ctx.globalAlpha=1.00;
ctx.fillStyle='black';
ctx.fillText('obstacle',ob.x+ob.w/2,ob.y+ob.h/2);
//
ctx.globalAlpha=0.250;
ctx.strokeStyle='gold';
ctx.strokeRect(p1.x,p1.y,p1.w,p1.h);
ctx.strokeStyle='purple';
ctx.strokeRect(p2.x,p2.y,p2.w,p2.h);
ctx.fillStyle='black';
ctx.globalAlpha=1.00;
ctx.fillText('start',p1.x+p1.w/2,p1.y+p1.h/2);
ctx.fillText('end',p2.x+p2.w/2,p2.y+p2.h/2);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
var mx=startX;
var my=startY;
if(mx>p1.x && mx<p1.x+p1.w && my>p1.y && my<p1.y+p1.h){
isDown=true;
dragging=p1;
}else if(mx>p2.x && mx<p2.x+p2.w && my>p2.y && my<p2.y+p2.h){
isDown=true;
dragging=p2;
}
}
function handleMouseUpOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// Put your mouseup stuff here
isDown=false;
dragging=null;
}
function handleMouseMove(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
//
dragging.x+=dx;
dragging.y+=dy;
//
draw();
//
setPlayerVertices(p1,p2);
var c=hasCollided(obVertices);
if(c.dx){
ctx.strokeStyle='gold';
ctx.strokeRect(p1.x+c.dx,p1.y+c.dy,p1.w,p1.h);
ctx.fillStyle='black';
ctx.fillText('hit',p1.x+c.dx+p1.w/2,p1.y+c.dy+p1.h/2);
line(c.s,c.i,'red');
}
}
function setPlayerVertices(p1,p2){
var tl1={x:p1.x, y:p1.y};
var tl2={x:p2.x, y:p2.y};
var tr1={x:p1.x+p1.w, y:p1.y};
var tr2={x:p2.x+p2.w, y:p2.y};
var br1={x:p1.x+p1.w, y:p1.y+p1.h};
var br2={x:p2.x+p2.w, y:p2.y+p2.h};
var bl1={x:p1.x, y:p1.y+p1.h};
var bl2={x:p2.x, y:p2.y+p2.h};
//
if(p1.x<=p2.x && p1.y<=p2.y){
s1=tr1; s2=br1; s3=bl1;
e1=tr2; e2=br2; e3=bl2;
o1=0; o2=1; o3=3; o4=0;
}else if(p1.x<=p2.x && p1.y>=p2.y){
s1=tl1; s2=tr1; s3=br1;
e1=tl2; e2=tr2; e3=br2;
o1=2; o2=3; o3=3; o4=0;
}else if(p1.x>=p2.x && p1.y<=p2.y){
s1=tl1; s2=br1; s3=bl1;
e1=tl2; e2=br2; e3=bl2;
o1=0; o2=1; o3=1; o4=2;
}else if(p1.x>=p2.x && p1.y>=p2.y){
s1=tl1; s2=tr1; s3=bl1;
e1=tl2; e2=tr2; e3=bl2;
o1=1; o2=2; o3=2; o4=3;
}
}
function hasCollided(o){
//
var i1=line2lineIntersection(s1,e1,o[o1],o[o2]);
var i2=line2lineIntersection(s2,e2,o[o1],o[o2]);
var i3=line2lineIntersection(s3,e3,o[o1],o[o2]);
var i4=line2lineIntersection(s1,e1,o[o3],o[o4]);
var i5=line2lineIntersection(s2,e2,o[o3],o[o4]);
var i6=line2lineIntersection(s3,e3,o[o3],o[o4]);
//
var tracks=[];
if(i1){tracks.push(track(s1,e1,i1));}
if(i2){tracks.push(track(s2,e2,i2));}
if(i3){tracks.push(track(s3,e3,i3));}
if(i4){tracks.push(track(s1,e1,i4));}
if(i5){tracks.push(track(s2,e2,i5));}
if(i6){tracks.push(track(s3,e3,i6));}
//
var nohitDist=10000000;
var minDistSq=nohitDist;
var halt={dx:null,dy:null,};
for(var i=0;i<tracks.length;i++){
var t=tracks[i];
var testdist=t.dx*t.dx+t.dy*t.dy;
if(testdist<minDistSq){
minDistSq=testdist;
halt.dx=t.dx;
halt.dy=t.dy;
halt.s=t.s;
halt.i=t.i;
}
}
return(halt);
}
//
function track(s,e,i){
dot(s);dot(i);line(s,i);line(i,e);
return({ dx:i.x-s.x, dy:i.y-s.y, s:s, i:i });
}
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}
function dot(pt){
ctx.beginPath();
ctx.arc(pt.x,pt.y,3,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
function line(p0,p1,stroke,lw){
ctx.beginPath();
ctx.moveTo(p0.x,p0.y);
ctx.lineTo(p1.x,p1.y);
ctx.lineWidth=lw || 1;
ctx.strokeStyle=stroke || 'gray';
ctx.stroke();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag start & end player position rects<br>The shortest segment intersecting the obstacle is red.<br>The repositioned player is shown on the obstacle.</h4>
<canvas id="canvas" width=400 height=400></canvas>