如何约束圆圈区域内的移动

时间:2011-12-15 06:16:21

标签: javascript geometry

这可能更像是几何相关的问题,但我试图将控制器限制在一个圆的区域内。我知道我必须触及Math.sin()和Math.cos()方法,但到目前为止我的尝试都没有结果。

enter image description here

这是jsfiddle: 到目前为止,我已经能够将它限制在一个看不见的方格。 http://jsfiddle.net/maGVK/

4 个答案:

答案 0 :(得分:6)

所以我终于能够在每个人的帮助下完成这个。

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(e.x, e.y);
        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));
}

您可以在此处查看结果:

http://jsfiddle.net/7Asn6/

答案 1 :(得分:1)

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(e.x, e.y);
    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));
}  

这可以完成工作,虽然运动不顺畅......需要更多的几何知识...... 小提琴:http://jsfiddle.net/cRxMa/

答案 2 :(得分:1)

只要你 规范化 每个数据点(预期位置),这个算法都是微不足道的,我试图在下面的函数中做到这一点:

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
    }   
}

所以在下面的简单图中,我刚刚在一个边是r * 2的正方形内刻了一个单位圆(r = 1)。您的画布尺寸必须是正方形。为了进一步简化计算,您只需要考虑四个象限中的一个 - 即右上象限。原因是欧几里德距离公式对每个坐标值进行平方,因此负值变为正值。

换句话说,最简单的方法是想象一个刻在画布上的圆圈,其中心也是画布的中心(所以(0,0)是中心而不是左上角 - 角落);接下来,画布和圆圈都缩小,直到圆圈的半径= 1.希望我已经在上面的函数中捕获了它。

enter image description here

答案 3 :(得分:0)

您好,感谢您分享您的解决方案。

你的jsfiddle帮助我约束旋转手柄的移动。

这是我使用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>

希望这有助于某人。