How to limit movement in a circle

This might be a more geometry related question, but I'm trying to limit the controller to a circle. I know that I need to touch the Math.sin () and Math.cos () methods, but so far my attempts have been fruitless.

enter image description here

Here is the jsfiddle: So far I have been able to hold it back to an invisible area. http://jsfiddle.net/maGVK/

+4
source share
4 answers

So, I finally was able to complete this with every help.

var pointerEl = document.getElementById("pointer"); var canvasEl = document.getElementById("canvas"); var canvas = { width: canvasEl.offsetWidth, height: canvasEl.offsetHeight, top: canvasEl.offsetTop, left: canvasEl.offsetLeft }; canvas.center = [canvas.left + canvas.width / 2, canvas.top + canvas.height / 2]; canvas.radius = canvas.width / 2; window.onmousemove = function(e) { var result = limit(ex, ey); pointer.style.left = result.x + "px"; pointer.style.top = result.y + "px"; } function limit(x, y) { var dist = distance([x, y], canvas.center); if (dist <= canvas.radius) { return {x: x, y: y}; } else { x = x - canvas.center[0]; y = y - canvas.center[1]; var radians = Math.atan2(y, x) return { x: Math.cos(radians) * canvas.radius + canvas.center[0], y: Math.sin(radians) * canvas.radius + canvas.center[1] } } } function distance(dot1, dot2) { var x1 = dot1[0], y1 = dot1[1], x2 = dot2[0], y2 = dot2[1]; return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } 

The result can be seen here:

http://jsfiddle.net/7Asn6/

+5
source
 var pointerEl = document.getElementById("pointer"); var canvasEl = document.getElementById("canvas"); var canvas = { width: canvasEl.offsetWidth, height: canvasEl.offsetHeight, top: canvasEl.offsetTop, left: canvasEl.offsetLeft }; canvas.center = [canvas.left + canvas.width / 2, canvas.top + canvas.height / 2]; canvas.radius = canvas.width / 2; window.onmousemove = function(e) { var result = limit(ex, ey); if (!result.limit) { pointer.style.left = result.x + "px"; pointer.style.top = result.y + "px"; } } function limit(x, y) { var dist = distance([x, y], canvas.center); if (dist <= canvas.radius) { return {x: x, y: y}; } else { return {limit: true}; } } function distance(dot1, dot2) { var x1 = dot1[0], y1 = dot1[1], x2 = dot2[0], y2 = dot2[1]; return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } 

this can do the job, although the movement is not smooth ... which will require more knowledge of geometry ...
fiddle: http://jsfiddle.net/cRxMa/

+1
source

This arithmetic is trivial if you normalize every data point (assumed position) that I tried to execute in the following function:

 function locatePoint(canvas_size, next_position) { // canvas_size & next_position are both 2-element arrays // (w, h) & (x, y) dist = function(x, y) { return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); }; x = next_position[0]; y = next_position[1]; rescaledX = x/(canvas_size[0]/2); rescaledY = y/(canvas_size[1]/2); if (distance(x, y) <= 1) { // the base case; position is w/in the circle } else { // position is outside the circle, so perhaps // do something like random select a new position, then // call this function again (recursively) passing in // that new position } } 

therefore, in the simple diagram below, I simply entered a unit circle (r = 1) inside a square whose sides are r * 2. However, the dimensions of your canvas need not be square. To simplify the calculation even more, you only need to consider one of the four quadrants - the upper right quadrant, say. The reason is that the Euclidean distance formula squares each coordinate value, so negative values ​​become positive.

In other words, the easiest way is to imagine a circle inscribed in your canvas and whose center is also the center of your canvas (therefore (0, 0) is not the center in the upper left corner); Then both the canvas and the circle are reduced until the circle has a radius = 1. I hope I captured this in the function above.

enter image description here

+1
source

Hi and thanks for sharing your solution.

Your jsfiddle helps me greatly limit the movement of the rotation knob.

Here is my solution using jQuery:

 function getBall(xVal, yVal, dxVal, dyVal, rVal, colorVal) { var ball = { x: xVal, lastX: xVal, y: yVal, lastY: yVal, dx: dxVal, dy: dyVal, r: rVal, color: colorVal, normX: 0, normY: 0 }; return ball; } var canvas = document.getElementById("myCanvas"); var xLabel = document.getElementById("x"); var yLabel = document.getElementById("y"); var dxLabel = document.getElementById("dx"); var dyLabel = document.getElementById("dy"); var ctx = canvas.getContext("2d"); var containerR = 200; canvas.width = containerR * 2; canvas.height = containerR * 2; canvas.style["border-radius"] = containerR + "px"; var balls = [ getBall(containerR, containerR * 2 - 30, 2, -2, 20, "#0095DD"), getBall(containerR, containerR * 2 - 50, 3, -3, 30, "#DD9500"), getBall(containerR, containerR * 2 - 60, -3, 4, 10, "#00DD95"), getBall(containerR, containerR * 2 / 5, -1.5, 3, 40, "#DD0095") ]; function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < balls.length; i++) { var curBall = balls[i]; ctx.beginPath(); ctx.arc(curBall.x, curBall.y, curBall.r, 0, Math.PI * 2); ctx.fillStyle = curBall.color; ctx.fill(); ctx.closePath(); curBall.lastX = curBall.x; curBall.lastY = curBall.y; curBall.x += curBall.dx; curBall.y += curBall.dy; var dx = curBall.x - containerR; var dy = curBall.y - containerR; var distanceFromCenter = Math.sqrt(dx * dx + dy * dy); if (distanceFromCenter >= containerR - curBall.r) { var normalMagnitude = distanceFromCenter; var normalX = dx / normalMagnitude; var normalY = dy / normalMagnitude; var tangentX = -normalY; var tangentY = normalX; var normalSpeed = -(normalX * curBall.dx + normalY * curBall.dy); var tangentSpeed = tangentX * curBall.dx + tangentY * curBall.dy; curBall.dx = normalSpeed * normalX + tangentSpeed * tangentX; curBall.dy = normalSpeed * normalY + tangentSpeed * tangentY; } xLabel.innerText = "x: " + curBall.x; yLabel.innerText = "y: " + curBall.y; dxLabel.innerText = "dx: " + curBall.dx; dyLabel.innerText = "dy: " + curBall.dy; } requestAnimationFrame(draw); } draw(); 
 canvas { background: #eee; } 
 <div id="x"></div> <div id="y"></div> <div id="dx"></div> <div id="dy"></div> <canvas id="myCanvas"></canvas> 

Hope this helps someone.

0
source

Source: https://habr.com/ru/post/1386457/


All Articles