Usando un cálculo de área de polígono, es increíblemente simple determinar si un búfer de coordenadas de mouse x, y se mueve técnica y matemáticamente en el sentido de las agujas del reloj o en el sentido contrario a las agujas del reloj:
let dir = Math.sign(coords.reduce((prev, coord, i) => prev + (coords[i+1].x - coord.x) * (coords[i+1].y + coord.y),0 ))Pero ese código simple siempre regresará en sentido horario o antihorario, que no es prácticamente lo que debería ser el resultado correcto.
Los movimientos rápidos hacia arriba y hacia abajo, o hacia la izquierda y hacia la derecha, o líneas muy aproximadamente rectas, técnicamente pueden moverse en el sentido de las agujas del reloj, pero no se mueven en el sentido de las agujas del reloj en el sentido común de las agujas del reloj: no hay una opción para "NI" .
¿Hay alguna manera de ajustar ese cálculo para determinar rápidamente si el 'sentido de las agujas del reloj' está más allá de un cierto umbral?
Bueno, lo que puedes hacer es
|y| > Eps donde Eps es el umbral que consideras para discriminar movimiento giratorio o líneas rectas Para hacerlo, puede, por ejemplo, echar un vistazo aquí https://dracoblue.net/dev/linear-least-squares-in-javascript/ y verá que en algún punto hay m (ángulo) y b (intersección )
function rotate(x, y, angle) { var radians = (Math.PI / 180) * angle, cos = Math.cos(radians), sin = Math.sin(radians), nx = (cos * x) + (sin * y), ny = (cos * y) - (sin * x); return [nx, ny]; } // supposing yourPoints = [[x0,y0], [x1,y1], ...] function checkStraight(yourPoints, epsilon = 1) /* code to get m and b from the link or any linear regression you prefer */ // get radiants const angle = Math.atan(m); // rotate by angle and decrease by intercept const translatedPoints = yourPoints.map(p => rotate(p[0], p[1] - b)) return translatedPoints.every(p => p[1] < epsilon) }No estoy seguro de cómo cambiar el cálculo del área del polígono para incluir su propio umbral, pero puede comparar el abs() del área de un círculo delimitador y establecer un porcentaje mínimo.
Encuentre el valor mayor entre el mínimo/máximo de x y el mínimo/máximo de y, y multiplíquelo por pi/4.
let circ = Math.PI/4 * Math.max( Math.max([...coords.x]) - Math.min([...coords.x]), Math.max([...coords.y]) - Math.min([...coords.y]) ); let dir = (Math.abs(area) / circ > 50%) ? Math.sign(area) : 0;Esto producirá -1 o +1 para movimientos en el sentido de las agujas del reloj que barren un área con más de "cincuenta por ciento de redondez aproximada" y CERO para movimientos que son demasiado oblicuos para ser considerados movimientos en el sentido de las agujas del reloj.
En la práctica, encontrará que max(X) - min(X) se puede evitar simplemente usando la diferencia entre el primer y el último punto en el búfer de coordenadas.
let diameter = Math.max( Math.abs(coords[0].x - coords.at(-1).x), Math.abs(coords[0].y - coords.at(-1).y) );Porque la captura del movimiento del mouse ocurre lo suficientemente rápido como para que no se note. Además, ahora tiene una información adicional, el diámetro, que puede usar para determinar "cuán grandes" son los movimientos en el sentido de las agujas del reloj.
Esto se puede hacer sin ninguna función trigonométrica y con solo una línea más de código.