Good evening. There is a div. How can I track which side the mouse is pointing at this div? That is, on a mousemove event, to track which side suggests on this div. From the beginning, I thought to track the coordinates of the mouse, taking into account the current and past points and determine the direction from them. But it turns out that somehow I need to track the direction of movement (that is, down / up / left / right), in addition to the coordinates. Please tell me the solution.

  • the difference between the coordinates of the current and previous points and will give you the direction - displacement vector - Igor
  • The fact is that it can work for two directions - that is, left / right or up / down. For all 4 directions such verification is not enough. - Drylozav
  • No, that's not the point. To set / describe the direction in mathematics there is a concept - a vector. How to find it - I already wrote to you. - Igor
  • Tell me, that is, with the help of the directional cosine, can I find the direction of motion of the vector? - Drylozav
  • You see, you have already started talking about cosine (and earlier it was only "down / up / left / right"), which means you understand that the cursor can move at an angle to the axes of coordinates. Yes you can. - Igor

3 answers 3

const DEG_TO_RAD = Math.PI / 180; const RAD_TO_DEG = 180 / Math.PI; const point = ( x = 0, y = 0 ) => ({ x, y }); const length = ( { x, y } ) => Math.sqrt( x * x + y * y ); const normalize = ( vector ) => { let vectorLength = length( vector ); let { x, y } = vector; return point( x / vectorLength, y / vectorLength ); }; const subtract = ( a, b ) => ({ x: ax - bx, y: ay - by }); const DIRECTIONS = { TOP: "top", RIGHT: "right", BOTTOM: "bottom", LEFT: "left" }; const defaultBorder = `3px solid black`; const getBorder = side => ({ borderTop: `${ side === DIRECTIONS.TOP ? defaultBorder : '' }`, borderRight: `${ side === DIRECTIONS.RIGHT ? defaultBorder : '' }`, borderBottom: `${ side === DIRECTIONS.BOTTOM ? defaultBorder : '' }`, borderLeft: `${ side === DIRECTIONS.LEFT ? defaultBorder : '' }`, }) const actionMap = { [ DIRECTIONS.TOP ]: element => Object.assign( element.style, getBorder( DIRECTIONS.TOP ) ), [ DIRECTIONS.RIGHT ]: element => Object.assign( element.style, getBorder( DIRECTIONS.RIGHT ) ), [ DIRECTIONS.BOTTOM ]: element => Object.assign( element.style, getBorder( DIRECTIONS.BOTTOM ) ), [ DIRECTIONS.LEFT ]: element => Object.assign( element.style, getBorder( DIRECTIONS.LEFT ) ), } let rect = document.body.querySelector('.rect'); let rectangle = rect.getBoundingClientRect(); let center = point( rectangle.width / 2 + rectangle.left, rectangle.height / 2 + rectangle.top ); document.addEventListener('mousemove', document_mouseMoveHandler); function document_mouseMoveHandler( { clientX, clientY } ){ let mouse = point( clientX, clientY ); let mc = subtract( mouse, center ); let direction = normalize( mc ); let angle = Math.atan2( direction.y, direction.x ) * RAD_TO_DEG; let type = getDirection( angle ); let action = actionMap[ type ]; action( rect ); } function getDirection( angle ){ if( angle <= -45 && angle > -130 ){ return DIRECTIONS.TOP; }else if( angle > -180 && angle <= -130 || angle <= 180 && angle > 130 ){ return DIRECTIONS.LEFT; }else if( angle > 45 && angle <= 130 ){ return DIRECTIONS.BOTTOM; }else if( angle <= 45 && angle > -45 ){ return DIRECTIONS.RIGHT; } } 
 .rect { width: 100px; height: 100px; background: tomato; position: absolute; top: 50%; left: 50%; transform: translate( -50%, -50% ); } 
 <div class="rect"></div> 

  • Say for clarity. You are here through the normalized vector, calculate the cosine guide? - Drylozav
  • @Drylozav yes, why? - user220409
  • Just wanted to understand the general idea, what would read your solution. Thank you very much. - Drylozav

I will offer an alternative option:

It is possible to check if each side (or segment) of the rectangle intersects with the segment, the beginning of which is the current position of the cursor, and the end is the center of the rectangle, and with which segment the intersection from that side was received and the mouse moves

Ie, in fact, all that needs to be done is to correctly check the intersection of segments, and the rest is trivial :)

 ;(function() { let rect = document.getElementById("rect"); let rectWidth = parseFloat(getComputedStyle(rect).width); let rectHeight = parseFloat(getComputedStyle(rect).height); let rectTopLeft = { x: parseFloat(getComputedStyle(rect).getPropertyValue("left")), y: parseFloat(getComputedStyle(rect).getPropertyValue("top")) }; let rectCenter = { x: rectTopLeft.x + rectWidth*0.5, y: rectTopLeft.y + rectHeight*0.5 }; let rectSides = { Top: { p0: {x: rectTopLeft.x, y: rectTopLeft.y}, p1: {x: rectTopLeft.x + rectWidth, y: rectTopLeft.y}, }, Left: { p0: {x: rectTopLeft.x, y: rectTopLeft.y}, p1: {x: rectTopLeft.x, y: rectTopLeft.y + rectHeight} }, Right: { p0: {x: rectTopLeft.x + rectWidth, y: rectTopLeft.y}, p1: {x: rectTopLeft.x + rectWidth, y: rectTopLeft.y + rectHeight} }, Bottom: { p0: {x: rectTopLeft.x, y: rectTopLeft.y + rectHeight}, p1: {x: rectTopLeft.x + rectWidth, y: rectTopLeft.y + rectHeight} } }; let sides = ["Top", "Left", "Right", "Bottom"]; function cross2d(a, b) { return ax*by - ay*bx; } function segmentsIntersect(p1, p2, p3, p4) { let v1 = cross2d( {x: p4.x - p3.x, y: p4.y - p3.y}, {x: p1.x - p3.x, y: p1.y - p3.y} ); let v2 = cross2d( {x: p4.x - p3.x, y: p4.y - p3.y}, {x: p2.x - p3.x, y: p2.y - p3.y} ); let v3 = cross2d( {x: p2.x - p1.x, y: p2.y - p1.y}, {x: p4.x - p1.x, y: p4.y - p1.y} ); let v4 = cross2d( {x: p2.x - p1.x, y: p2.y - p1.y}, {x: p3.x - p1.x, y: p3.y - p1.y} ); return v1*v2 < 0 && v3*v4 < 0; } document.onmousemove = function(e) { let mx = e.clientX, my = e.clientY; sides.forEach(function(side) { if (segmentsIntersect({x: mx, y: my}, rectCenter, rectSides[side].p0, rectSides[side].p1)) { rect.style["border" + side] = "4px solid #f00"; } else { rect.style["border" + side] = ""; } }); } })(); 
 #rect { width: 100px; height: 100px; background: #668; position: absolute; top: 30%; left: 40%; } 
 <div id="rect"></div> 

    No need cosines. On a hover event, save the x, y coordinates and the on = 1 switch. On the move event, you get x1 and y1, and if the switch is on, compare the coordinates and get the direction. Well, the switch to zero, so that no longer counted until you leave the area.

    • For those who are minus, please write why it does not work, there is a chance that I will understand. - Sergey Panasenko